diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 1565be3..0000000 --- a/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -*.tfstate -*.tfstate.backup -.terraform -provider.tf -*.tfvars -**/*.tfvars -provider.tf -.github -.circleci diff --git a/.terraform.lock.hcl b/.terraform.lock.hcl deleted file mode 100644 index e99dc12..0000000 --- a/.terraform.lock.hcl +++ /dev/null @@ -1,117 +0,0 @@ -# This file is maintained automatically by "terraform init". -# Manual edits may be lost in future updates. - -provider "registry.terraform.io/datadog/datadog" { - version = "3.1.2" - constraints = ">= 2.12.0, >= 2.13.0" - hashes = [ - "h1:lG4q9P7EMfrsCq/28SOac51iG2v/ZWSDsndtjeVyShQ=", - "zh:206a91983c7bd4ff3c1036d03608965037d6813122bc7b308a8c5bce1a0e868c", - "zh:355f88c1e3a383538d5713844f7829d78595789416d3abdf54da28c11e5ec386", - "zh:5d6980b8a2b983337e84cae494f88fd4eef6fc28376ff942f2fd4ceb163fd2b9", - "zh:63b36609bc5f574ceced3a311aed1141d9a6202e7f80fcd301b0db918e7e71c3", - "zh:83c6c3fa1c1b95dd2f20511bdd785ec41feb33bdbf1b73f34f8e8fba53b8bf41", - "zh:8eb74bfbe3b03fe6edb2b3d99306479344f3dbbf37d776b773ca3eed18b3557b", - "zh:9523fef89c62e4e5c207593f16a054bb378729760b777282f80af66f64290afc", - "zh:a4b25aa3d174062f6bcf12da2a9b749af4aa1474cdd88b1d42fd64575fe35536", - "zh:aa9486e8256f83a0a22c636ac1e8f677dcbcb2017a7a399da601cb8eff9ac49a", - "zh:c2cc7a5f29aadf27fcf42b9ad410b838a8259e803a6e82eccf5087744bcbdc04", - "zh:e21631e8b139b7e9632e1107a0db9ea8364a0fdfdb72b1d7d2e14148d1de57e8", - "zh:f7dba38c2fb09676a2a5f444b1e251349d0c060d837cf8e1f3e1046947effb4a", - "zh:f820dd9e935bf28e7f4b1c96a236175990d478d5f48c43ea344d574340b16b07", - ] -} - -provider "registry.terraform.io/hashicorp/archive" { - version = "2.2.0" - constraints = ">= 2.2.0" - hashes = [ - "h1:2K5LQkuWRS2YN1/YoNaHn9MAzjuTX8Gaqy6i8Mbfv8Y=", - "zh:06bd875932288f235c16e2237142b493c2c2b6aba0e82e8c85068332a8d2a29e", - "zh:0c681b481372afcaefddacc7ccdf1d3bb3a0c0d4678a526bc8b02d0c331479bc", - "zh:100fc5b3fc01ea463533d7bbfb01cb7113947a969a4ec12e27f5b2be49884d6c", - "zh:55c0d7ddddbd0a46d57c51fcfa9b91f14eed081a45101dbfc7fd9d2278aa1403", - "zh:73a5dd68379119167934c48afa1101b09abad2deb436cd5c446733e705869d6b", - "zh:841fc4ac6dc3479981330974d44ad2341deada8a5ff9e3b1b4510702dfbdbed9", - "zh:91be62c9b41edb137f7f835491183628d484e9d6efa82fcb75cfa538c92791c5", - "zh:acd5f442bd88d67eb948b18dc2ed421c6c3faee62d3a12200e442bfff0aa7d8b", - "zh:ad5720da5524641ad718a565694821be5f61f68f1c3c5d2cfa24426b8e774bef", - "zh:e63f12ea938520b3f83634fc29da28d92eed5cfbc5cc8ca08281a6a9c36cca65", - "zh:f6542918faa115df46474a36aabb4c3899650bea036b5f8a5e296be6f8f25767", - ] -} - -provider "registry.terraform.io/hashicorp/aws" { - version = "3.48.0" - constraints = ">= 2.0.0" - hashes = [ - "h1:HY/knz06L5OaxmLsuOevFA6PgF7eJKoQSZLlX2IqubU=", - "zh:1de9f52bc5c254fc021a4fdb285fca5cf7665e9eda890ac24aa7af8469654cc9", - "zh:2faf10c36dfaf6a97fb6a4c877ae9be61cb6bb81ee666f3455f156116b20c7a4", - "zh:3dad064853e24c0854c3e47c67f9e77c11319e52f0f3525a2583db13a272af6d", - "zh:56e9363542b5c745110b83f3904524669bb801f62db928d42860202ba3f48b51", - "zh:591088a86f9c9826d1b6918964386ca04b3d4e521efea9a5f00152d134162664", - "zh:baf5afc4b38b4bc9010123b1251fd7af8b68828fda22b67bd4e4f631bd19671a", - "zh:d3963400ef625433ea7d1fbabb564ac0aafaabb67c138f4a2954f05813f4cbd5", - "zh:d67856355bc746924bbdfcd4709afe9ebf8ccd5092fb10d6cb5fa1f19e6c2f43", - "zh:db99519a33a12b4f5965bf7127ed92759242e694b5ab1680aab6345d0102a200", - "zh:e44aea91718a15b96d903f60ac8cf5f913c6828c860035993c9bd1b872d84159", - "zh:fc25605dafb055d9138d90a837f5ae9ee96bcd4f8a2a89c4180573f6ea8fda66", - ] -} - -provider "registry.terraform.io/hashicorp/external" { - version = "2.1.0" - constraints = ">= 1.2.0" - hashes = [ - "h1:LTl5CGW8wiIEe16AC4MtXN/95xWWNDbap70zJsBTk0w=", - "zh:0d83ffb72fbd08986378204a7373d8c43b127049096eaf2765bfdd6b00ad9853", - "zh:7577d6edc67b1e8c2cf62fe6501192df1231d74125d90e51d570d586d95269c5", - "zh:9c669ded5d5affa4b2544952c4b6588dfed55260147d24ced02dca3a2829f328", - "zh:a404d46f2831f90633947ab5d57e19dbfe35b3704104ba6ec80bcf50b058acfd", - "zh:ae1caea1c936d459ceadf287bb5c5bd67b5e2a7819df6f5c4114b7305df7f822", - "zh:afb4f805477694a4b9dde86b268d2c0821711c8aab1c6088f5f992228c4c06fb", - "zh:b993b4a1de8a462643e78f4786789e44ce5064b332fee1cb0d6250ed085561b8", - "zh:c84b2c13fa3ea2c0aa7291243006d560ce480a5591294b9001ce3742fc9c5791", - "zh:c8966f69b7eccccb771704fd5335923692eccc9e0e90cb95d14538fe2e92a3b8", - "zh:d5fe68850d449b811e633a300b114d0617df6d450305e8251643b4d143dc855b", - "zh:ddebfd1e674ba336df09b1f27bbaa0e036c25b7a7087dc8081443f6e5954028b", - ] -} - -provider "registry.terraform.io/hashicorp/local" { - version = "2.1.0" - constraints = ">= 1.3.0" - hashes = [ - "h1:KfieWtVyGWwplSoLIB5usKAUnrIkDQBkWaR5TI+4WYg=", - "zh:0f1ec65101fa35050978d483d6e8916664b7556800348456ff3d09454ac1eae2", - "zh:36e42ac19f5d68467aacf07e6adcf83c7486f2e5b5f4339e9671f68525fc87ab", - "zh:6db9db2a1819e77b1642ec3b5e95042b202aee8151a0256d289f2e141bf3ceb3", - "zh:719dfd97bb9ddce99f7d741260b8ece2682b363735c764cac83303f02386075a", - "zh:7598bb86e0378fd97eaa04638c1a4c75f960f62f69d3662e6d80ffa5a89847fe", - "zh:ad0a188b52517fec9eca393f1e2c9daea362b33ae2eb38a857b6b09949a727c1", - "zh:c46846c8df66a13fee6eff7dc5d528a7f868ae0dcf92d79deaac73cc297ed20c", - "zh:dc1a20a2eec12095d04bf6da5321f535351a594a636912361db20eb2a707ccc4", - "zh:e57ab4771a9d999401f6badd8b018558357d3cbdf3d33cc0c4f83e818ca8e94b", - "zh:ebdcde208072b4b0f8d305ebf2bfdc62c926e0717599dcf8ec2fd8c5845031c3", - "zh:ef34c52b68933bedd0868a13ccfd59ff1c820f299760b3c02e008dc95e2ece91", - ] -} - -provider "registry.terraform.io/hashicorp/template" { - version = "2.2.0" - constraints = ">= 2.0.0" - hashes = [ - "h1:0wlehNaxBX7GJQnPfQwTNvvAf38Jm0Nv7ssKGMaG6Og=", - "zh:01702196f0a0492ec07917db7aaa595843d8f171dc195f4c988d2ffca2a06386", - "zh:09aae3da826ba3d7df69efeb25d146a1de0d03e951d35019a0f80e4f58c89b53", - "zh:09ba83c0625b6fe0a954da6fbd0c355ac0b7f07f86c91a2a97849140fea49603", - "zh:0e3a6c8e16f17f19010accd0844187d524580d9fdb0731f675ffcf4afba03d16", - "zh:45f2c594b6f2f34ea663704cc72048b212fe7d16fb4cfd959365fa997228a776", - "zh:77ea3e5a0446784d77114b5e851c970a3dde1e08fa6de38210b8385d7605d451", - "zh:8a154388f3708e3df5a69122a23bdfaf760a523788a5081976b3d5616f7d30ae", - "zh:992843002f2db5a11e626b3fc23dc0c87ad3729b3b3cff08e32ffb3df97edbde", - "zh:ad906f4cebd3ec5e43d5cd6dc8f4c5c9cc3b33d2243c89c5fc18f97f7277b51d", - "zh:c979425ddb256511137ecd093e23283234da0154b7fa8b21c2687182d9aea8b2", - ] -} diff --git a/.terraform/modules/datadog-integration b/.terraform/modules/datadog-integration new file mode 160000 index 0000000..59c8066 --- /dev/null +++ b/.terraform/modules/datadog-integration @@ -0,0 +1 @@ +Subproject commit 59c8066eceee715d72f18dfd64836abb777aa22b diff --git a/.terraform/modules/datadog-integration.all_label b/.terraform/modules/datadog-integration.all_label new file mode 160000 index 0000000..dc69999 --- /dev/null +++ b/.terraform/modules/datadog-integration.all_label @@ -0,0 +1 @@ +Subproject commit dc699992922b452ccc521c3dfe9c9c5c1f8376af diff --git a/.terraform/modules/datadog-integration.artifact b/.terraform/modules/datadog-integration.artifact new file mode 160000 index 0000000..6f24262 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact @@ -0,0 +1 @@ +Subproject commit 6f24262652a52a055de711cfee0e3dfac5221e0e diff --git a/.terraform/modules/datadog-integration.artifact.this/LICENSE b/.terraform/modules/datadog-integration.artifact.this/LICENSE new file mode 100755 index 0000000..c844c70 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017-2020 Cloud Posse, LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/.terraform/modules/datadog-integration.artifact.this/Makefile b/.terraform/modules/datadog-integration.artifact.this/Makefile new file mode 100755 index 0000000..97d8087 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/Makefile @@ -0,0 +1,10 @@ +SHELL := /bin/bash + +# List of targets the `readme` target should call before generating the readme +export README_DEPS ?= docs/targets.md docs/terraform.md + +-include $(shell curl -sSL -o .build-harness "https://git.io/build-harness"; echo .build-harness) + +## Lint terraform code +lint: + $(SELF) terraform/install terraform/get-modules terraform/get-plugins terraform/lint terraform/validate diff --git a/.terraform/modules/datadog-integration.artifact.this/README.md b/.terraform/modules/datadog-integration.artifact.this/README.md new file mode 100755 index 0000000..32950e4 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/README.md @@ -0,0 +1,938 @@ + +# terraform-null-label [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-null-label.svg)](https://github.com/cloudposse/terraform-null-label/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) + + +[![README Header][readme_header_img]][readme_header_link] + +[![Cloud Posse][logo]](https://cpco.io/homepage) + + + +Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + +This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. +However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). +So if you prefer the term `stage` to `environment` +you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. +- If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. +- If you want the attributes in a different order, you can specify that, too, with the `label_order` list. +- You can set a maximum length for the name, and the module will create a unique name that fits within that length. +- You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. +- The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + +It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. +For example, if you have 10 instances, there should be 10 different labels. +However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + +All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + +**NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. +With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + +- Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. +- Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. +- Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. + + +--- + +This project is part of our comprehensive ["SweetOps"](https://cpco.io/sweetops) approach towards DevOps. +[][share_email] +[][share_googleplus] +[][share_facebook] +[][share_reddit] +[][share_linkedin] +[][share_twitter] + + +[![Terraform Open Source Modules](https://docs.cloudposse.com/images/terraform-open-source-modules.svg)][terraform_modules] + + + +It's 100% Open Source and licensed under the [APACHE2](LICENSE). + + + + + + + +We literally have [*hundreds of terraform modules*][terraform_modules] that are Open Source and well-maintained. Check them out! + + + + + + + +## Security & Compliance [](https://bridgecrew.io/) + +Security scanning is graciously provided by Bridgecrew. Bridgecrew is the leading fully hosted, cloud-native solution providing continuous Terraform security and compliance. + +| Benchmark | Description | +|--------|---------------| +| [![Infrastructure Security](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/general)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=INFRASTRUCTURE+SECURITY) | Infrastructure Security Compliance | +| [![CIS KUBERNETES](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_kubernetes)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+KUBERNETES+V1.5) | Center for Internet Security, KUBERNETES Compliance | +| [![CIS AWS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_aws)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AWS+V1.2) | Center for Internet Security, AWS Compliance | +| [![CIS AZURE](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_azure)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AZURE+V1.1) | Center for Internet Security, AZURE Compliance | +| [![PCI-DSS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/pci)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=PCI-DSS+V3.2) | Payment Card Industry Data Security Standards Compliance | +| [![NIST-800-53](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/nist)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=NIST-800-53) | National Institute of Standards and Technology Compliance | +| [![ISO27001](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/iso)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=ISO27001) | Information Security Management System, ISO/IEC 27001 Compliance | +| [![SOC2](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/soc2)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=SOC2)| Service Organization Control 2 Compliance | +| [![CIS GCP](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_gcp)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+GCP+V1.1) | Center for Internet Security, GCP Compliance | +| [![HIPAA](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/hipaa)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=HIPAA) | Health Insurance Portability and Accountability Compliance | + + + +## Usage + + +**IMPORTANT:** We do not pin modules to versions in our examples because of the +difficulty of keeping the versions in the documentation in sync with the latest released versions. +We highly recommend that in your code you pin the version to the exact version you are +using so that your infrastructure remains stable, and update versions in a +systematic way so that they do not catch you by surprise. + +Also, because of a bug in the Terraform registry ([hashicorp/terraform#21417](https://github.com/hashicorp/terraform/issues/21417)), +the registry shows many of our inputs as required when in fact they are optional. +The table below correctly indicates which inputs are required. + + +### Defaults + +Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. +The context object is a single object that contains all the input values for `terraform-null-label`. +However, each input value can also be specified individually by name as a standard Terraform variable, +and the value of those variables, when set to something other than `null`, will override the value +in the context object. In order to allow chaining of these objects, where the context object input to one +module is transformed and passed to the next module, all the variables default to `null` or empty collections. +The actual default values used when nothing is explicitly set are describe in the documentation below. + +For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, +`terraform-null-label` will actually use the default delimiter `-` (hyphen). + +A non-obvious but intentional consequence of this design is that once a module sets a non-default value, +future modules in the chain cannot reset the value back to the original default. Insted, the new setting +becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, +so once a tag is added, it will remain in the tag set and cannot be removed, although its value can +be overwritten. + +### Simple Example + +```hcl +module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} +``` + +This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` +(you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + +Now reference the label when creating an instance: + +```hcl +resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags +} +``` + +Or define a security group: + +```hcl +resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} +``` + + +### Advanced Example + +Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + +```hcl +module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] +} + +module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] +} +``` + +
+ +### Advanced Example 2 + +Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + +```hcl +tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } +] +``` + +Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + +```hcl +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} +``` + +
+ +### Advanced Example 3 + +See [complete example](./examples/complete) for even more examples. + +This example shows how you can pass the `context` output of one label module to the next label_module, +allowing you to create one label that has the base set of values, and then creating every extra label +as a derivative of that. + +
Click to show + +```hcl +module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} +``` + +This creates label outputs like this: + +```hcl +label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" +} +label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } +} +label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } +} +label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" +} +label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" +} +label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } +} +label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" +} +label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, +] +label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" +} +label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } +} +label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } +} +label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" +} + +``` + +
+ + + + + + + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + + + + +## Share the Love + +Like this project? Please give it a ★ on [our GitHub](https://github.com/cloudposse/terraform-null-label)! (it helps us **a lot**) + +Are you using this project or any of our other projects? Consider [leaving a testimonial][testimonial]. =) + + +## Related Projects + +Check out these related projects. + +- [terraform-terraform-label](https://github.com/cloudposse/terraform-terraform-label) - Terraform Module to define a consistent naming convention by (namespace, environment, stage, name, [attributes]) + + + +## Help + +**Got a question?** We got answers. + +File a GitHub [issue](https://github.com/cloudposse/terraform-null-label/issues), send us an [email][email] or join our [Slack Community][slack]. + +[![README Commercial Support][readme_commercial_support_img]][readme_commercial_support_link] + +## DevOps Accelerator for Startups + + +We are a [**DevOps Accelerator**][commercial_support]. We'll help you build your cloud infrastructure from the ground up so you can own it. Then we'll show you how to operate it and stick around for as long as you need us. + +[![Learn More](https://img.shields.io/badge/learn%20more-success.svg?style=for-the-badge)][commercial_support] + +Work directly with our team of DevOps experts via email, slack, and video conferencing. + +We deliver 10x the value for a fraction of the cost of a full-time engineer. Our track record is not even funny. If you want things done right and you need it done FAST, then we're your best bet. + +- **Reference Architecture.** You'll get everything you need from the ground up built using 100% infrastructure as code. +- **Release Engineering.** You'll have end-to-end CI/CD with unlimited staging environments. +- **Site Reliability Engineering.** You'll have total visibility into your apps and microservices. +- **Security Baseline.** You'll have built-in governance with accountability and audit logs for all changes. +- **GitOps.** You'll be able to operate your infrastructure via Pull Requests. +- **Training.** You'll receive hands-on training so your team can operate what we build. +- **Questions.** You'll have a direct line of communication between our teams via a Shared Slack channel. +- **Troubleshooting.** You'll get help to triage when things aren't working. +- **Code Reviews.** You'll receive constructive feedback on Pull Requests. +- **Bug Fixes.** We'll rapidly work with you to fix any bugs in our projects. + +## Slack Community + +Join our [Open Source Community][slack] on Slack. It's **FREE** for everyone! Our "SweetOps" community is where you get to talk with others who share a similar vision for how to rollout and manage infrastructure. This is the best place to talk shop, ask questions, solicit feedback, and work together as a community to build totally *sweet* infrastructure. + +## Discourse Forums + +Participate in our [Discourse Forums][discourse]. Here you'll find answers to commonly asked questions. Most questions will be related to the enormous number of projects we support on our GitHub. Come here to collaborate on answers, find solutions, and get ideas about the products and services we value. It only takes a minute to get started! Just sign in with SSO using your GitHub account. + +## Newsletter + +Sign up for [our newsletter][newsletter] that covers everything on our technology radar. Receive updates on what we're up to on GitHub as well as awesome new projects we discover. + +## Office Hours + +[Join us every Wednesday via Zoom][office_hours] for our weekly "Lunch & Learn" sessions. It's **FREE** for everyone! + +[![zoom](https://img.cloudposse.com/fit-in/200x200/https://cloudposse.com/wp-content/uploads/2019/08/Powered-by-Zoom.png")][office_hours] + +## Contributing + +### Bug Reports & Feature Requests + +Please use the [issue tracker](https://github.com/cloudposse/terraform-null-label/issues) to report any bugs or file feature requests. + +### Developing + +If you are interested in being a contributor and want to get involved in developing this project or [help out](https://cpco.io/help-out) with our other projects, we would love to hear from you! Shoot us an [email][email]. + +In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. + + 1. **Fork** the repo on GitHub + 2. **Clone** the project to your own machine + 3. **Commit** changes to your own branch + 4. **Push** your work back up to your fork + 5. Submit a **Pull Request** so that we can review your changes + +**NOTE:** Be sure to merge the latest changes from "upstream" before making a pull request! + + +## Copyright + +Copyright © 2017-2021 [Cloud Posse, LLC](https://cpco.io/copyright) + + + +## License + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +See [LICENSE](LICENSE) for full details. + +```text +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +``` + + + + + + + + + +## Trademarks + +All other trademarks referenced herein are the property of their respective owners. + +## About + +This project is maintained and funded by [Cloud Posse, LLC][website]. Like it? Please let us know by [leaving a testimonial][testimonial]! + +[![Cloud Posse][logo]][website] + +We're a [DevOps Professional Services][hire] company based in Los Angeles, CA. We ❤️ [Open Source Software][we_love_open_source]. + +We offer [paid support][commercial_support] on all of our projects. + +Check out [our other projects][github], [follow us on twitter][twitter], [apply for a job][jobs], or [hire us][hire] to help with your cloud strategy and implementation. + + + +### Contributors + + +| [![Erik Osterman][osterman_avatar]][osterman_homepage]
[Erik Osterman][osterman_homepage] | [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]
[Andriy Knysh][aknysh_homepage] | [![Igor Rodionov][goruha_avatar]][goruha_homepage]
[Igor Rodionov][goruha_homepage] | [![Sergey Vasilyev][s2504s_avatar]][s2504s_homepage]
[Sergey Vasilyev][s2504s_homepage] | [![Michael Pereira][MichaelPereira_avatar]][MichaelPereira_homepage]
[Michael Pereira][MichaelPereira_homepage] | [![Jamie Nelson][Jamie-BitFlight_avatar]][Jamie-BitFlight_homepage]
[Jamie Nelson][Jamie-BitFlight_homepage] | [![Vladimir][SweetOps_avatar]][SweetOps_homepage]
[Vladimir][SweetOps_homepage] | [![Daren Desjardins][darend_avatar]][darend_homepage]
[Daren Desjardins][darend_homepage] | [![Maarten van der Hoef][maartenvanderhoef_avatar]][maartenvanderhoef_homepage]
[Maarten van der Hoef][maartenvanderhoef_homepage] | [![Adam Tibbing][tibbing_avatar]][tibbing_homepage]
[Adam Tibbing][tibbing_homepage] | +|---|---|---|---|---|---|---|---|---|---| + + + [osterman_homepage]: https://github.com/osterman + [osterman_avatar]: https://img.cloudposse.com/150x150/https://github.com/osterman.png + [aknysh_homepage]: https://github.com/aknysh + [aknysh_avatar]: https://img.cloudposse.com/150x150/https://github.com/aknysh.png + [goruha_homepage]: https://github.com/goruha + [goruha_avatar]: https://img.cloudposse.com/150x150/https://github.com/goruha.png + [s2504s_homepage]: https://github.com/s2504s + [s2504s_avatar]: https://img.cloudposse.com/150x150/https://github.com/s2504s.png + [MichaelPereira_homepage]: https://github.com/MichaelPereira + [MichaelPereira_avatar]: https://img.cloudposse.com/150x150/https://github.com/MichaelPereira.png + [Jamie-BitFlight_homepage]: https://github.com/Jamie-BitFlight + [Jamie-BitFlight_avatar]: https://img.cloudposse.com/150x150/https://github.com/Jamie-BitFlight.png + [SweetOps_homepage]: https://github.com/SweetOps + [SweetOps_avatar]: https://img.cloudposse.com/150x150/https://github.com/SweetOps.png + [darend_homepage]: https://github.com/darend + [darend_avatar]: https://img.cloudposse.com/150x150/https://github.com/darend.png + [maartenvanderhoef_homepage]: https://github.com/maartenvanderhoef + [maartenvanderhoef_avatar]: https://img.cloudposse.com/150x150/https://github.com/maartenvanderhoef.png + [tibbing_homepage]: https://github.com/tibbing + [tibbing_avatar]: https://img.cloudposse.com/150x150/https://github.com/tibbing.png + +[![README Footer][readme_footer_img]][readme_footer_link] +[![Beacon][beacon]][website] + + [logo]: https://cloudposse.com/logo-300x69.svg + [docs]: https://cpco.io/docs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=docs + [website]: https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=website + [github]: https://cpco.io/github?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=github + [jobs]: https://cpco.io/jobs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=jobs + [hire]: https://cpco.io/hire?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=hire + [slack]: https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=slack + [linkedin]: https://cpco.io/linkedin?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=linkedin + [twitter]: https://cpco.io/twitter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=twitter + [testimonial]: https://cpco.io/leave-testimonial?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=testimonial + [office_hours]: https://cloudposse.com/office-hours?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=office_hours + [newsletter]: https://cpco.io/newsletter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=newsletter + [discourse]: https://ask.sweetops.com/?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=discourse + [email]: https://cpco.io/email?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=email + [commercial_support]: https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=commercial_support + [we_love_open_source]: https://cpco.io/we-love-open-source?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=we_love_open_source + [terraform_modules]: https://cpco.io/terraform-modules?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=terraform_modules + [readme_header_img]: https://cloudposse.com/readme/header/img + [readme_header_link]: https://cloudposse.com/readme/header/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_header_link + [readme_footer_img]: https://cloudposse.com/readme/footer/img + [readme_footer_link]: https://cloudposse.com/readme/footer/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_footer_link + [readme_commercial_support_img]: https://cloudposse.com/readme/commercial-support/img + [readme_commercial_support_link]: https://cloudposse.com/readme/commercial-support/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_commercial_support_link + [share_twitter]: https://twitter.com/intent/tweet/?text=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_linkedin]: https://www.linkedin.com/shareArticle?mini=true&title=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_reddit]: https://reddit.com/submit/?url=https://github.com/cloudposse/terraform-null-label + [share_facebook]: https://facebook.com/sharer/sharer.php?u=https://github.com/cloudposse/terraform-null-label + [share_googleplus]: https://plus.google.com/share?url=https://github.com/cloudposse/terraform-null-label + [share_email]: mailto:?subject=terraform-null-label&body=https://github.com/cloudposse/terraform-null-label + [beacon]: https://ga-beacon.cloudposse.com/UA-76589703-4/cloudposse/terraform-null-label?pixel&cs=github&cm=readme&an=terraform-null-label diff --git a/.terraform/modules/datadog-integration.artifact.this/README.yaml b/.terraform/modules/datadog-integration.artifact.this/README.yaml new file mode 100755 index 0000000..42bdb84 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/README.yaml @@ -0,0 +1,618 @@ +name: terraform-null-label +tags: +- aws +- terraform +- terraform-modules +- naming-convention +- name +- namespace +- stage +categories: +- terraform-modules/supported +license: APACHE2 +github_repo: cloudposse/terraform-null-label +badges: +- name: Latest Release + image: https://img.shields.io/github/release/cloudposse/terraform-null-label.svg + url: https://github.com/cloudposse/terraform-null-label/releases/latest +- name: Slack Community + image: https://slack.cloudposse.com/badge.svg + url: https://slack.cloudposse.com +related: +- name: terraform-terraform-label + description: Terraform Module to define a consistent naming convention by (namespace, + environment, stage, name, [attributes]) + url: https://github.com/cloudposse/terraform-terraform-label +description: |- + Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + + This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. + However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). + So if you prefer the term `stage` to `environment` + you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. + - If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. + - If you want the attributes in a different order, you can specify that, too, with the `label_order` list. + - You can set a maximum length for the name, and the module will create a unique name that fits within that length. + - You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. + - The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + + It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. + For example, if you have 10 instances, there should be 10 different labels. + However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + + All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + + **NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. + With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + + - Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. + - Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. + - Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. +usage: |- + ### Defaults + + Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. + The context object is a single object that contains all the input values for `terraform-null-label`. + However, each input value can also be specified individually by name as a standard Terraform variable, + and the value of those variables, when set to something other than `null`, will override the value + in the context object. In order to allow chaining of these objects, where the context object input to one + module is transformed and passed to the next module, all the variables default to `null` or empty collections. + The actual default values used when nothing is explicitly set are describe in the documentation below. + + For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, + `terraform-null-label` will actually use the default delimiter `-` (hyphen). + + A non-obvious but intentional consequence of this design is that once a module sets a non-default value, + future modules in the chain cannot reset the value back to the original default. Insted, the new setting + becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, + so once a tag is added, it will remain in the tag set and cannot be removed, although its value can + be overwritten. + + ### Simple Example + + ```hcl + module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + ``` + + This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` + (you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + + Now reference the label when creating an instance: + + ```hcl + resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags + } + ``` + + Or define a security group: + + ```hcl + resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + } + ``` + + + ### Advanced Example + + Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + + ```hcl + module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] + } + + module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] + } + ``` + +
+ + ### Advanced Example 2 + + Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + + ```hcl + tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } + ] + ``` + + Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + + ```hcl + ################################ + # terraform-null-label example # + ################################ + module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } + } + + ####################### + # Launch template # + ####################### + resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } + } + + ###################### + # Autoscaling group # + ###################### + resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps + } + ``` + +
+ + ### Advanced Example 3 + + See [complete example](./examples/complete) for even more examples. + + This example shows how you can pass the `context` output of one label module to the next label_module, + allowing you to create one label that has the base set of values, and then creating every extra label + as a derivative of that. + +
Click to show + + ```hcl + module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } + } + + module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } + } + + module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } + } + ``` + + This creates label outputs like this: + + ```hcl + label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" + } + label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } + } + label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + } + label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" + } + label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } + } + label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" + } + label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, + ] + label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" + } + label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } + } + label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + } + label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + + ``` + +
+ +include: +- docs/targets.md +- docs/terraform.md +contributors: +- name: Erik Osterman + github: osterman +- name: Andriy Knysh + github: aknysh +- name: Igor Rodionov + github: goruha +- name: Sergey Vasilyev + github: s2504s +- name: Michael Pereira + github: MichaelPereira +- name: Jamie Nelson + github: Jamie-BitFlight +- name: Vladimir + github: SweetOps +- name: Daren Desjardins + github: darend +- name: Maarten van der Hoef + github: maartenvanderhoef +- name: Adam Tibbing + github: tibbing diff --git a/.terraform/modules/datadog-integration.artifact.this/docs/targets.md b/.terraform/modules/datadog-integration.artifact.this/docs/targets.md new file mode 100755 index 0000000..3dce8b3 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/docs/targets.md @@ -0,0 +1,12 @@ + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + diff --git a/.terraform/modules/datadog-integration.artifact.this/docs/terraform.md b/.terraform/modules/datadog-integration.artifact.this/docs/terraform.md new file mode 100755 index 0000000..d4f48f4 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/docs/terraform.md @@ -0,0 +1,54 @@ + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars b/.terraform/modules/datadog-integration.artifact.this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars new file mode 100755 index 0000000..f7c725f --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars @@ -0,0 +1,12 @@ +namespace = "eg" +stage = "prod" +name = "app" + +tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" +} + +additional_tag_map = { + propagate_at_launch = "true" +} diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/autoscalinggroup/context.tf b/.terraform/modules/datadog-integration.artifact.this/examples/autoscalinggroup/context.tf new file mode 100755 index 0000000..b97f05f --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/autoscalinggroup/context.tf @@ -0,0 +1,216 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/autoscalinggroup/main.tf b/.terraform/modules/datadog-integration.artifact.this/examples/autoscalinggroup/main.tf new file mode 100755 index 0000000..f0d3aa6 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/autoscalinggroup/main.tf @@ -0,0 +1,104 @@ +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + + context = module.this.context +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template { + id = aws_launch_template.default.id + version = "$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} + +################################ +# Provider # +################################ +provider "aws" { + region = "eu-west-1" + + # Make it faster by skipping unneeded checks here + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +############################################################## +# Data sources to get VPC, subnets and security group details +############################################################## +data "aws_vpc" "default" { + default = true +} + +data "aws_subnet_ids" "all" { + vpc_id = data.aws_vpc.default.id +} + +data "aws_security_group" "default" { + vpc_id = data.aws_vpc.default.id + name = "default" +} + +data "aws_ami" "amazon_linux" { + most_recent = true + + owners = ["amazon"] + + filter { + name = "name" + + values = [ + "amzn-ami-hvm-*-x86_64-gp2", + ] + } + + filter { + name = "owner-alias" + + values = [ + "amazon", + ] + } +} + diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/autoscalinggroup/outputs.tf b/.terraform/modules/datadog-integration.artifact.this/examples/autoscalinggroup/outputs.tf new file mode 100755 index 0000000..f8fcce5 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/autoscalinggroup/outputs.tf @@ -0,0 +1,12 @@ +# terraform-null-label example used here: Output list of tags applied in each format +output "tags_as_list_of_maps" { + value = module.label.tags_as_list_of_maps +} + +output "tags" { + value = module.label.tags +} + +output "id" { + value = module.label.id +} diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/autoscalinggroup/versions.tf b/.terraform/modules/datadog-integration.artifact.this/examples/autoscalinggroup/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/autoscalinggroup/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/complete/complete.auto.tfvars b/.terraform/modules/datadog-integration.artifact.this/examples/complete/complete.auto.tfvars new file mode 100755 index 0000000..e7bc519 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/complete/complete.auto.tfvars @@ -0,0 +1,10 @@ +namespace = "cp" +environment = "uw2" +stage = "prd" +name = "null-label" + +delimiter = "" +id_length_limit = 6 + +label_key_case = "lower" +label_value_case = "upper" diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/complete/context.tf b/.terraform/modules/datadog-integration.artifact.this/examples/complete/context.tf new file mode 100755 index 0000000..973d4dc --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/complete/context.tf @@ -0,0 +1,217 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/complete/label1.tf b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label1.tf new file mode 100755 index 0000000..8da353b --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label1.tf @@ -0,0 +1,42 @@ +module "label1" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label1" { + value = { + id = module.label1.id + name = module.label1.name + namespace = module.label1.namespace + stage = module.label1.stage + attributes = module.label1.attributes + delimiter = module.label1.delimiter + } +} + +output "label1_tags" { + value = module.label1.tags +} + +output "label1_context" { + value = module.label1.context +} + +output "label1_normalized_context" { + value = module.label1.normalized_context +} + + + diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/complete/label1t1.tf b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label1t1.tf new file mode 100755 index 0000000..2bcb362 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label1t1.tf @@ -0,0 +1,18 @@ +module "label1t1" { + source = "../../" + + id_length_limit = 28 + + context = module.label1.context +} + +output "label1t1" { + value = { + id = module.label1t1.id + id_full = module.label1t1.id_full + } +} + +output "label1t1_tags" { + value = module.label1t1.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/complete/label1t2.tf b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label1t2.tf new file mode 100755 index 0000000..5df651e --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label1t2.tf @@ -0,0 +1,18 @@ +module "label1t2" { + source = "../../" + + id_length_limit = 29 + + context = module.label1.context +} + +output "label1t2" { + value = { + id = module.label1t2.id + id_full = module.label1t2.id_full + } +} + +output "label1t2_tags" { + value = module.label1t2.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/complete/label2.tf b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label2.tf new file mode 100755 index 0000000..faf7450 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label2.tf @@ -0,0 +1,42 @@ +module "label2" { + source = "../../" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + regex_replace_chars = "/[^a-zA-Z0-9-+]/" + + additional_tag_map = { + propagate_at_launch = "true" + additional_tag = "yes" + } + + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +output "label2" { + value = { + id = module.label2.id + name = module.label2.name + namespace = module.label2.namespace + stage = module.label2.stage + attributes = module.label2.attributes + delimiter = module.label2.delimiter + } +} + +output "label2_tags" { + value = module.label2.tags +} + +output "label2_tags_as_list_of_maps" { + value = module.label2.tags_as_list_of_maps +} + +output "label2_context" { + value = module.label2.context +} diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/complete/label3c.tf b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label3c.tf new file mode 100755 index 0000000..338a636 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label3c.tf @@ -0,0 +1,36 @@ +module "label3c" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3c" { + value = { + id = module.label3c.id + name = module.label3c.name + namespace = module.label3c.namespace + stage = module.label3c.stage + attributes = module.label3c.attributes + delimiter = module.label3c.delimiter + } +} + +output "label3c_tags" { + value = module.label3c.tags +} + +output "label3c_context" { + value = module.label3c.context +} + +output "label3c_normalized_context" { + value = module.label3c.normalized_context +} diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/complete/label3n.tf b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label3n.tf new file mode 100755 index 0000000..ca51282 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label3n.tf @@ -0,0 +1,36 @@ +module "label3n" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.normalized_context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3n" { + value = { + id = module.label3n.id + name = module.label3n.name + namespace = module.label3n.namespace + stage = module.label3n.stage + attributes = module.label3n.attributes + delimiter = module.label3n.delimiter + } +} + +output "label3n_tags" { + value = module.label3n.tags +} + +output "label3n_context" { + value = module.label3n.context +} + +output "label3n_normalized_context" { + value = module.label3n.normalized_context +} diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/complete/label4.tf b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label4.tf new file mode 100755 index 0000000..74e3ca1 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label4.tf @@ -0,0 +1,34 @@ +module "label4" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + name = "Example Cluster" + attributes = ["big", "fat", "honking", "cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label4" { + value = { + id = module.label4.id + name = module.label4.name + namespace = module.label4.namespace + stage = module.label4.stage + attributes = module.label4.attributes + delimiter = module.label4.delimiter + } +} + +output "label4_tags" { + value = module.label4.tags +} + +output "label4_context" { + value = module.label4.context +} diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/complete/label5.tf b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label5.tf new file mode 100755 index 0000000..0f0a76e --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label5.tf @@ -0,0 +1,33 @@ +module "label5" { + source = "../../" + enabled = false + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + } +} + +output "label5" { + value = { + id = module.label5.id + name = module.label5.name + namespace = module.label5.namespace + stage = module.label5.stage + attributes = module.label5.attributes + delimiter = module.label5.delimiter + } +} + +output "label5_tags" { + value = module.label5.tags +} + +output "label5_context" { + value = module.label5.context +} diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/complete/label6f.tf b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label6f.tf new file mode 100755 index 0000000..1ce1bab --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label6f.tf @@ -0,0 +1,20 @@ +module "label6f" { + source = "../../" + + delimiter = "~" + id_length_limit = 0 + + # Use values from tfvars + context = module.this.context +} + +output "label6f" { + value = { + id = module.label6f.id + id_full = module.label6f.id_full + } +} + +output "label6f_tags" { + value = module.label6f.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/complete/label6t.tf b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label6t.tf new file mode 100755 index 0000000..b5d9bc1 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label6t.tf @@ -0,0 +1,19 @@ +module "label6t" { + source = "../../" + + # Use values from tfvars, + # specifically: complete.auto.tfvars + context = module.this.context +} + +output "label6t" { + value = { + id = module.label6t.id + id_full = module.label6t.id_full + id_length_limit = module.this.context.id_length_limit + } +} + +output "label6t_tags" { + value = module.label6t.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/complete/label7.tf b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label7.tf new file mode 100755 index 0000000..bb365d4 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label7.tf @@ -0,0 +1,44 @@ +module "label7a" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + } +} + +module "label7" { + source = "../../" + + attributes = ["nodegroup"] + + context = module.label7a.context +} + + +output "label7" { + value = { + id = module.label7.id + name = module.label7.name + namespace = module.label7.namespace + stage = module.label7.stage + attributes = module.label7.attributes + delimiter = module.label7.delimiter + } +} + +output "label7_id" { + value = module.label7.id +} + +output "label7_attributes" { + value = module.label7.attributes +} + +output "label7_context" { + value = module.label7.context +} diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/complete/label8d.tf b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label8d.tf new file mode 100755 index 0000000..4252419 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label8d.tf @@ -0,0 +1,44 @@ +module "label8d" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8d_context" { + source = "../../" + + context = module.label8d.context +} + +output "label8d_context_id" { + value = module.label8d_context.id +} + +output "label8d_context_context" { + value = module.label8d_context.context +} + +output "label8d_context_tags" { + value = module.label8d_context.tags +} + +output "label8d_id" { + value = module.label8d.id +} + +output "label8d_context" { + value = module.label8d.context +} + +output "label8d_tags" { + value = module.label8d.tags +} diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/complete/label8dcd.tf b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label8dcd.tf new file mode 100755 index 0000000..ccdae21 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label8dcd.tf @@ -0,0 +1,24 @@ +module "label8dcd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "x" +} + +module "label8dcd_context" { + source = "../../" + + context = module.label8dcd.context +} + +output "label8dcd_context_id" { + value = module.label8dcd_context.id +} + +output "label8dcd_id" { + value = module.label8dcd.id +} diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/complete/label8dnd.tf b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label8dnd.tf new file mode 100755 index 0000000..2edb378 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label8dnd.tf @@ -0,0 +1,24 @@ +module "label8dnd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "" +} + +module "label8dnd_context" { + source = "../../" + + context = module.label8dnd.context +} + +output "label8dnd_context_id" { + value = module.label8dnd_context.id +} + +output "label8dnd_id" { + value = module.label8dnd.id +} diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/complete/label8l.tf b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label8l.tf new file mode 100755 index 0000000..7462f9e --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label8l.tf @@ -0,0 +1,46 @@ +module "label8l" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "lower" + label_value_case = "lower" + + tags = { + "kubernetes.io/cluster/" = "shared" + "upperTEST" = "testUPPER" + } +} + +module "label8l_context" { + source = "../../" + + context = module.label8l.context +} + +output "label8l_context_id" { + value = module.label8l_context.id +} + +output "label8l_context_context" { + value = module.label8l_context.context +} + +output "label8l_context_tags" { + value = module.label8l_context.tags +} + +output "label8l_id" { + value = module.label8l.id +} + +output "label8l_context" { + value = module.label8l.context +} + +output "label8l_tags" { + value = module.label8l.tags +} diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/complete/label8n.tf b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label8n.tf new file mode 100755 index 0000000..fd4ad57 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label8n.tf @@ -0,0 +1,45 @@ +module "label8n" { + source = "../../" + + enabled = true + namespace = "EG" + environment = "demo" + name = "blue" + attributes = ["eks", "ClusteR"] + delimiter = "-" + label_value_case = "none" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8n_context" { + source = "../../" + + context = module.label8n.context +} + +output "label8n_context_id" { + value = module.label8n_context.id +} + +output "label8n_context_context" { + value = module.label8n_context.context +} + +output "label8n_context_tags" { + value = module.label8n_context.tags +} + +output "label8n_id" { + value = module.label8n.id +} + +output "label8n_context" { + value = module.label8n.context +} + +output "label8n_tags" { + value = module.label8n.tags +} diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/complete/label8t.tf b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label8t.tf new file mode 100755 index 0000000..cb54c7a --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label8t.tf @@ -0,0 +1,45 @@ +module "label8t" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["EKS", "cluster"] + delimiter = "-" + label_key_case = "title" + label_value_case = "title" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8t_context" { + source = "../../" + + context = module.label8t.context +} + +output "label8t_context_id" { + value = module.label8t_context.id +} + +output "label8t_context_context" { + value = module.label8t_context.context +} + +output "label8t_context_tags" { + value = module.label8t_context.tags +} + +output "label8t_id" { + value = module.label8t.id +} + +output "label8t_context" { + value = module.label8t.context +} + +output "label8t_tags" { + value = module.label8t.tags +} diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/complete/label8u.tf b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label8u.tf new file mode 100755 index 0000000..499535b --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/complete/label8u.tf @@ -0,0 +1,50 @@ +module "label8u" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "upper" + label_value_case = "upper" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8u_context" { + source = "../../" + + context = module.label8u.context +} + +output "label8u_context_id" { + value = module.label8u_context.id +} + +output "label8u_context_context" { + value = module.label8u_context.context +} + +// debug +output "label8u_context_normalized_context" { + value = module.label8u_context.normalized_context +} + +output "label8u_context_tags" { + value = module.label8u_context.tags +} + +output "label8u_id" { + value = module.label8u.id +} + +output "label8u_context" { + value = module.label8u.context +} + +output "label8u_tags" { + value = module.label8u.tags +} diff --git a/.terraform/modules/datadog-integration.artifact.this/examples/complete/versions.tf b/.terraform/modules/datadog-integration.artifact.this/examples/complete/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/examples/complete/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/context.tf b/.terraform/modules/datadog-integration.artifact.this/exports/context.tf old mode 100644 new mode 100755 similarity index 87% rename from context.tf rename to .terraform/modules/datadog-integration.artifact.this/exports/context.tf index 307f711..81f99b4 --- a/context.tf +++ b/.terraform/modules/datadog-integration.artifact.this/exports/context.tf @@ -1,3 +1,23 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + module "this" { source = "cloudposse/label/null" version = "0.24.1" # requires Terraform >= 0.13.0 @@ -180,5 +200,3 @@ variable "label_value_case" { } } #### End of copy of cloudposse/terraform-null-label/variables.tf - - diff --git a/.terraform/modules/datadog-integration.artifact.this/main.tf b/.terraform/modules/datadog-integration.artifact.this/main.tf new file mode 100755 index 0000000..0deda2b --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/main.tf @@ -0,0 +1,146 @@ +locals { + + defaults = { + label_order = ["namespace", "environment", "stage", "name", "attributes"] + regex_replace_chars = "/[^-a-zA-Z0-9]/" + delimiter = "-" + replacement = "" + id_length_limit = 0 + id_hash_length = 5 + label_key_case = "title" + label_value_case = "lower" + } + + # So far, we have decided not to allow overriding replacement or id_hash_length + replacement = local.defaults.replacement + id_hash_length = local.defaults.id_hash_length + + # The values provided by variables supersede the values inherited from the context object, + # except for tags and attributes which are merged. + input = { + # It would be nice to use coalesce here, but we cannot, because it + # is an error for all the arguments to coalesce to be empty. + enabled = var.enabled == null ? var.context.enabled : var.enabled + namespace = var.namespace == null ? var.context.namespace : var.namespace + environment = var.environment == null ? var.context.environment : var.environment + stage = var.stage == null ? var.context.stage : var.stage + name = var.name == null ? var.context.name : var.name + delimiter = var.delimiter == null ? var.context.delimiter : var.delimiter + # modules tack on attributes (passed by var) to the end of the list (passed by context) + attributes = compact(distinct(concat(coalesce(var.context.attributes, []), coalesce(var.attributes, [])))) + tags = merge(var.context.tags, var.tags) + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + label_order = var.label_order == null ? var.context.label_order : var.label_order + regex_replace_chars = var.regex_replace_chars == null ? var.context.regex_replace_chars : var.regex_replace_chars + id_length_limit = var.id_length_limit == null ? var.context.id_length_limit : var.id_length_limit + label_key_case = var.label_key_case == null ? lookup(var.context, "label_key_case", null) : var.label_key_case + label_value_case = var.label_value_case == null ? lookup(var.context, "label_value_case", null) : var.label_value_case + } + + + enabled = local.input.enabled + regex_replace_chars = coalesce(local.input.regex_replace_chars, local.defaults.regex_replace_chars) + + # string_label_names are names of inputs that are strings (not list of strings) used as labels + string_label_names = ["name", "namespace", "environment", "stage"] + normalized_labels = { for k in local.string_label_names : k => + local.input[k] == null ? "" : replace(local.input[k], local.regex_replace_chars, local.replacement) + } + normalized_attributes = compact(distinct([for v in local.input.attributes : replace(v, local.regex_replace_chars, local.replacement)])) + + formatted_labels = { for k in local.string_label_names : k => local.label_value_case == "none" ? local.normalized_labels[k] : + local.label_value_case == "title" ? title(lower(local.normalized_labels[k])) : + local.label_value_case == "upper" ? upper(local.normalized_labels[k]) : lower(local.normalized_labels[k]) + } + + attributes = compact(distinct([ + for v in local.normalized_attributes : (local.label_value_case == "none" ? v : + local.label_value_case == "title" ? title(lower(v)) : + local.label_value_case == "upper" ? upper(v) : lower(v)) + ])) + + name = local.formatted_labels["name"] + namespace = local.formatted_labels["namespace"] + environment = local.formatted_labels["environment"] + stage = local.formatted_labels["stage"] + + delimiter = local.input.delimiter == null ? local.defaults.delimiter : local.input.delimiter + label_order = local.input.label_order == null ? local.defaults.label_order : coalescelist(local.input.label_order, local.defaults.label_order) + id_length_limit = local.input.id_length_limit == null ? local.defaults.id_length_limit : local.input.id_length_limit + label_key_case = local.input.label_key_case == null ? local.defaults.label_key_case : local.input.label_key_case + label_value_case = local.input.label_value_case == null ? local.defaults.label_value_case : local.input.label_value_case + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + + tags = merge(local.generated_tags, local.input.tags) + + tags_as_list_of_maps = flatten([ + for key in keys(local.tags) : merge( + { + key = key + value = local.tags[key] + }, var.additional_tag_map) + ]) + + tags_context = { + # For AWS we need `Name` to be disambiguated since it has a special meaning + name = local.id + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = local.id_context.attributes + } + + generated_tags = { + for l in keys(local.tags_context) : + local.label_key_case == "upper" ? upper(l) : ( + local.label_key_case == "lower" ? lower(l) : title(lower(l)) + ) => local.tags_context[l] if length(local.tags_context[l]) > 0 + } + + id_context = { + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = join(local.delimiter, local.attributes) + } + + labels = [for l in local.label_order : local.id_context[l] if length(local.id_context[l]) > 0] + + id_full = join(local.delimiter, local.labels) + # Create a truncated ID if needed + delimiter_length = length(local.delimiter) + # Calculate length of normal part of ID, leaving room for delimiter and hash + id_truncated_length_limit = local.id_length_limit - (local.id_hash_length + local.delimiter_length) + # Truncate the ID and ensure a single (not double) trailing delimiter + id_truncated = local.id_truncated_length_limit <= 0 ? "" : "${trimsuffix(substr(local.id_full, 0, local.id_truncated_length_limit), local.delimiter)}${local.delimiter}" + # Support usages that disallow numeric characters. Would prefer tr 0-9 q-z but Terraform does not support it. + id_hash_plus = "${md5(local.id_full)}qrstuvwxyz" + id_hash_case = local.label_value_case == "title" ? title(local.id_hash_plus) : local.label_value_case == "upper" ? upper(local.id_hash_plus) : local.label_value_case == "lower" ? lower(local.id_hash_plus) : local.id_hash_plus + id_hash = replace(local.id_hash_case, local.regex_replace_chars, local.replacement) + # Create the short ID by adding a hash to the end of the truncated ID + id_short = substr("${local.id_truncated}${local.id_hash}", 0, local.id_length_limit) + id = local.id_length_limit != 0 && length(local.id_full) > local.id_length_limit ? local.id_short : local.id_full + + + # Context of this label to pass to other label modules + output_context = { + enabled = local.enabled + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + delimiter = local.delimiter + attributes = local.attributes + tags = local.tags + additional_tag_map = local.additional_tag_map + label_order = local.label_order + regex_replace_chars = local.regex_replace_chars + id_length_limit = local.id_length_limit + label_key_case = local.label_key_case + label_value_case = local.label_value_case + } + +} diff --git a/.terraform/modules/datadog-integration.artifact.this/outputs.tf b/.terraform/modules/datadog-integration.artifact.this/outputs.tf new file mode 100755 index 0000000..87ad1be --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/outputs.tf @@ -0,0 +1,88 @@ +output "id" { + value = local.enabled ? local.id : "" + description = "Disambiguated ID restricted to `id_length_limit` characters in total" +} + +output "id_full" { + value = local.enabled ? local.id_full : "" + description = "Disambiguated ID not restricted in length" +} + +output "enabled" { + value = local.enabled + description = "True if module is enabled, false otherwise" +} + +output "namespace" { + value = local.enabled ? local.namespace : "" + description = "Normalized namespace" +} + +output "environment" { + value = local.enabled ? local.environment : "" + description = "Normalized environment" +} + +output "name" { + value = local.enabled ? local.name : "" + description = "Normalized name" +} + +output "stage" { + value = local.enabled ? local.stage : "" + description = "Normalized stage" +} + +output "delimiter" { + value = local.enabled ? local.delimiter : "" + description = "Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes`" +} + +output "attributes" { + value = local.enabled ? local.attributes : [] + description = "List of attributes" +} + +output "tags" { + value = local.enabled ? local.tags : {} + description = "Normalized Tag map" +} + +output "additional_tag_map" { + value = local.additional_tag_map + description = "The merged additional_tag_map" +} + +output "label_order" { + value = local.label_order + description = "The naming order actually used to create the ID" +} + +output "regex_replace_chars" { + value = local.regex_replace_chars + description = "The regex_replace_chars actually used to create the ID" +} + +output "id_length_limit" { + value = local.id_length_limit + description = "The id_length_limit actually used to create the ID, with `0` meaning unlimited" +} + +output "tags_as_list_of_maps" { + value = local.tags_as_list_of_maps + description = "Additional tags as a list of maps, which can be used in several AWS resources" +} + +output "normalized_context" { + value = local.output_context + description = "Normalized context of this module" +} + +output "context" { + value = local.input + description = <<-EOT + Merged but otherwise unmodified input to this module, to be used as context input to other modules. + Note: this version will have null values as defaults, not the values actually used as defaults. +EOT +} + diff --git a/.terraform/modules/datadog-integration.artifact.this/test/Makefile b/.terraform/modules/datadog-integration.artifact.this/test/Makefile new file mode 100755 index 0000000..ea15d62 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/test/Makefile @@ -0,0 +1,43 @@ +TEST_HARNESS ?= https://github.com/cloudposse/test-harness.git +TEST_HARNESS_BRANCH ?= master +TEST_HARNESS_PATH = $(realpath .test-harness) +BATS_ARGS ?= --tap +BATS_LOG ?= test.log + +# Define a macro to run the tests +define RUN_TESTS +@echo "Running tests in $(1)" +@cd $(1) && bats $(BATS_ARGS) $(addsuffix .bats,$(addprefix $(TEST_HARNESS_PATH)/test/terraform/,$(TESTS))) +endef + +default: all + +-include Makefile.* + +## Provision the test-harnesss +.test-harness: + [ -d $@ ] || git clone --depth=1 -b $(TEST_HARNESS_BRANCH) $(TEST_HARNESS) $@ + +## Initialize the tests +init: .test-harness + +## Install all dependencies (OS specific) +deps:: + @exit 0 + +## Clean up the test harness +clean: + [ "$(TEST_HARNESS_PATH)" == "/" ] || rm -rf $(TEST_HARNESS_PATH) + +## Run all tests +all: module examples/complete + +## Run basic sanity checks against the module itself +module: export TESTS ?= installed lint get-modules module-pinning get-plugins provider-pinning validate terraform-docs input-descriptions output-descriptions +module: deps + $(call RUN_TESTS, ../) + +## Run tests against example +examples/complete: export TESTS ?= installed lint get-modules get-plugins validate init plan apply +examples/complete: deps + $(call RUN_TESTS, ../$@) diff --git a/.terraform/modules/datadog-integration.artifact.this/test/Makefile.alpine b/.terraform/modules/datadog-integration.artifact.this/test/Makefile.alpine new file mode 100755 index 0000000..7925b18 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/test/Makefile.alpine @@ -0,0 +1,5 @@ +ifneq (,$(wildcard /sbin/apk)) +## Install all dependencies for alpine +deps:: init + @apk add --update terraform-docs@cloudposse json2hcl@cloudposse +endif diff --git a/.terraform/modules/datadog-integration.artifact.this/test/src/Makefile b/.terraform/modules/datadog-integration.artifact.this/test/src/Makefile new file mode 100755 index 0000000..b772822 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/test/src/Makefile @@ -0,0 +1,30 @@ +export TF_CLI_ARGS_init ?= -get-plugins=true +export TERRAFORM_VERSION ?= $(shell curl -s https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r -M '.current_version' | cut -d. -f1-2) + +.DEFAULT_GOAL : all +.PHONY: all + +## Default target +all: test + +.PHONY : init +## Initialize tests +init: + @exit 0 + +.PHONY : test +## Run tests +test: init + go mod download + go test -v -timeout 60m -run TestExamplesComplete + +## Run tests in docker container +docker/test: + docker run --name terratest --rm -it -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e GITHUB_TOKEN \ + -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" \ + -v $(CURDIR)/../../:/module/ cloudposse/test-harness:latest -C /module/test/src test + +.PHONY : clean +## Clean up files +clean: + rm -rf ../../examples/complete/*.tfstate* diff --git a/.terraform/modules/datadog-integration.artifact.this/test/src/examples_complete_test.go b/.terraform/modules/datadog-integration.artifact.this/test/src/examples_complete_test.go new file mode 100755 index 0000000..156e293 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/test/src/examples_complete_test.go @@ -0,0 +1,293 @@ +package test + +import ( + "fmt" + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" + "github.com/qdm12/reprint" + "github.com/stretchr/testify/assert" +) + +type NLContext struct { + AdditionalTagMap map[string]string `json:"additional_tag_map"` + Attributes []string `json:"attributes"` + Delimiter interface{} `json:"delimiter"` + Enabled bool `json:"enabled"` + Environment interface{} `json:"environment"` + LabelOrder []string `json:"label_order"` + Name interface{} `json:"name"` + Namespace interface{} `json:"namespace"` + RegexReplaceChars interface{} `json:"regex_replace_chars"` + Stage interface{} `json:"stage"` + Tags map[string]string `json:"tags"` +} + +// Test the Terraform module in examples/complete using Terratest. +func TestExamplesComplete(t *testing.T) { + t.Parallel() + + terraformOptions := &terraform.Options{ + // The path to where our Terraform code is located + TerraformDir: "../../examples/complete", + Upgrade: true, + } + + // At the end of the test, run `terraform destroy` to clean up any resources that were created + defer terraform.Destroy(t, terraformOptions) + + // This will run `terraform init` and `terraform apply` and fail the test if there are any errors + terraform.InitAndApply(t, terraformOptions) + + expectedLabel1Context := NLContext{ + Enabled: true, + Namespace: "CloudPosse", + Environment: "UAT", + Stage: "build", + Name: "Winston Churchroom", + Attributes: []string{"fire", "water", "earth", "air"}, + Delimiter: "-", + LabelOrder: []string{"name", "environment", "stage", "attributes"}, + Tags: map[string]string{ + "City": "Dublin", + "Environment": "Private", + }, + AdditionalTagMap: map[string]string{}, + } + + var expectedLabel1NormalizedContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel1NormalizedContext) + expectedLabel1NormalizedContext.Namespace = "cloudposse" + expectedLabel1NormalizedContext.Environment = "uat" + expectedLabel1NormalizedContext.Name = "winstonchurchroom" + expectedLabel1NormalizedContext.RegexReplaceChars = "/[^-a-zA-Z0-9]/" + expectedLabel1NormalizedContext.Tags = map[string]string{ + "City": "Dublin", + "Environment": "Private", + "Namespace": "cloudposse", + "Stage": "build", + "Name": "winstonchurchroom-uat-build-fire-water-earth-air", + "Attributes": "fire-water-earth-air", + } + + var label1NormalizedContext, label1Context NLContext + // Run `terraform output` to get the value of an output variable + label1 := terraform.OutputMap(t, terraformOptions, "label1") + label1Tags := terraform.OutputMap(t, terraformOptions, "label1_tags") + terraform.OutputStruct(t, terraformOptions, "label1_normalized_context", &label1NormalizedContext) + terraform.OutputStruct(t, terraformOptions, "label1_context", &label1Context) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1["id"]) + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1Tags["Name"]) + assert.Equal(t, "Dublin", label1Tags["City"]) + assert.Equal(t, "Private", label1Tags["Environment"]) + assert.Equal(t, expectedLabel1NormalizedContext, label1NormalizedContext) + assert.Equal(t, expectedLabel1Context, label1Context) + + label1t1 := terraform.OutputMap(t, terraformOptions, "label1t1") + label1t1Tags := terraform.OutputMap(t, terraformOptions, "label1t1_tags") + assert.Equal(t, "winstonchurchroom-uat-6a0b34", label1t1["id"], + "Extra hash character should be added when trailing delimiter is removed") + assert.Equal(t, label1["id"], label1t1["id_full"], "id_full should not be truncated") + assert.Equal(t, label1t1["id"], label1t1Tags["Name"], "Name tag should match ID") + + label1t2 := terraform.OutputMap(t, terraformOptions, "label1t2") + label1t2Tags := terraform.OutputMap(t, terraformOptions, "label1t2_tags") + assert.Equal(t, "winstonchurchroom-uat-b-6a0b3", label1t2["id"]) + assert.Equal(t, label1t2["id"], label1t2Tags["Name"], "Name tag should match ID") + + // Run `terraform output` to get the value of an output variable + label2 := terraform.OutputMap(t, terraformOptions, "label2") + label2Tags := terraform.OutputMap(t, terraformOptions, "label2_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2["id"]) + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2Tags["Name"]) + assert.Equal(t, "London", label2Tags["City"]) + assert.Equal(t, "Public", label2Tags["Environment"]) + + var expectedLabel3cContext, label3cContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel3cContext) + expectedLabel3cContext.Name = "Starfish" + expectedLabel3cContext.Stage = "release" + expectedLabel3cContext.Delimiter = "." + expectedLabel3cContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3cContext.Tags["Eat"] = "Carrot" + expectedLabel3cContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3c := terraform.OutputMap(t, terraformOptions, "label3c") + label3cTags := terraform.OutputMap(t, terraformOptions, "label3c_tags") + terraform.OutputStruct(t, terraformOptions, "label3c_context", &label3cContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3c["id"]) + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3cTags["Name"]) + assert.Equal(t, expectedLabel3cContext, label3cContext) + + var expectedLabel3nContext, label3nContext NLContext + _ = reprint.FromTo(&expectedLabel1NormalizedContext, &expectedLabel3nContext) + expectedLabel3nContext.Name = "Starfish" + expectedLabel3nContext.Stage = "release" + expectedLabel3nContext.Delimiter = "." + expectedLabel3nContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3nContext.Tags["Eat"] = "Carrot" + expectedLabel3nContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3n := terraform.OutputMap(t, terraformOptions, "label3n") + label3nTags := terraform.OutputMap(t, terraformOptions, "label3n_tags") + terraform.OutputStruct(t, terraformOptions, "label3n_context", &label3nContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3n["id"]) + assert.Equal(t, label1Tags["Name"], label3nTags["Name"], + "Tag from label1 normalized context should overwrite label3n generated tag") + assert.Equal(t, expectedLabel3nContext, label3nContext) + + // Run `terraform output` to get the value of an output variable + label4 := terraform.OutputMap(t, terraformOptions, "label4") + label4Tags := terraform.OutputMap(t, terraformOptions, "label4_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4["id"]) + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4Tags["Name"]) + + // Run `terraform output` to get the value of an output variable + label5 := terraform.OutputMap(t, terraformOptions, "label5") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "", label5["id"]) + + label6f := terraform.OutputMap(t, terraformOptions, "label6f") + label6fTags := terraform.OutputMap(t, terraformOptions, "label6f_tags") + // Test of setting var.label_key_case = "lower", var.label_value_case = "upper" + assert.Equal(t, "CP~UW2~PRD~NULL-LABEL", label6f["id_full"]) + assert.Equal(t, label6f["id_full"], label6f["id"], "id should not be truncated") + assert.Equal(t, label6f["id"], label6fTags["name"], "Name tag should match ID") + + label6t := terraform.OutputMap(t, terraformOptions, "label6t") + label6tTags := terraform.OutputMap(t, terraformOptions, "label6t_tags") + assert.Equal(t, "CPUW2PRDNULL-LABEL", label6t["id_full"]) + assert.NotEqual(t, label6t["id_full"], label6t["id"], "id should be truncated") + assert.Equal(t, label6t["id"], label6tTags["name"], "Name tag should match ID") + assert.Equal(t, label6t["id_length_limit"], fmt.Sprintf("%d", len(label6t["id"])), + "Truncated ID length should equal length limit") + + label7 := terraform.OutputMap(t, terraformOptions, "label7") + assert.Equal(t, "eg-demo-blue-cluster-nodegroup", label7["id"], "var.attributes should be appended after context.attributes") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter=""` returns expected value of id, context id + label8dndID := terraform.Output(t, terraformOptions, "label8dnd_id") + label8dndContextID := terraform.Output(t, terraformOptions, "label8dnd_context_id") + assert.Equal(t, "egdemobluecluster", label8dndID) + assert.Equal(t, label8dndID, label8dndContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter="x"` returns expected value of id, context id + label8dcdID := terraform.Output(t, terraformOptions, "label8dcd_id") + label8dcdContextID := terraform.Output(t, terraformOptions, "label8dcd_context_id") + assert.Equal(t, "egxdemoxbluexcluster", label8dcdID) + assert.Equal(t, label8dcdID, label8dcdContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=lower` returns expected values of id, tags, context tags + label8dExpectedTags := map[string]string{ + "Attributes": "cluster", + "Environment": "demo", + "Name": "eg-demo-blue-cluster", + "Namespace": "eg", + "kubernetes.io/cluster/": "shared", + } + + label8dID := terraform.Output(t, terraformOptions, "label8d_id") + label8dContextID := terraform.Output(t, terraformOptions, "label8d_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8dID) + assert.Equal(t, label8dID, label8dContextID, "ID and context ID should be equal") + + label8dTags := terraform.OutputMap(t, terraformOptions, "label8d_tags") + label8dContextTags := terraform.OutputMap(t, terraformOptions, "label8d_context_tags") + + assert.Exactly(t, label8dExpectedTags, label8dTags, "generated tags are different from expected") + assert.Exactly(t, label8dTags, label8dContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=lower` and `label_value_case=lower` returns expected values of id, tags, context tags + label8lExpectedTags := map[string]string{ + "attributes": "cluster", + "environment": "demo", + "name": "eg-demo-blue-cluster", + "namespace": "eg", + "kubernetes.io/cluster/": "shared", + "upperTEST": "testUPPER", + } + + label8lID := terraform.Output(t, terraformOptions, "label8l_id") + label8lContextID := terraform.Output(t, terraformOptions, "label8l_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8lID) + assert.Equal(t, label8lID, label8lContextID, "ID and context ID should be equal") + + label8lTags := terraform.OutputMap(t, terraformOptions, "label8l_tags") + label8lContextTags := terraform.OutputMap(t, terraformOptions, "label8l_context_tags") + + assert.Exactly(t, label8lExpectedTags, label8lTags, "generated tags are different from expected") + assert.Exactly(t, label8lTags, label8lContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=title` returns expected values of id, tags, context tags + label8tExpectedTags := map[string]string{ + "Attributes": "Eks-Cluster", + "Environment": "Demo", + "Name": "Eg-Demo-Blue-Eks-Cluster", + "Namespace": "Eg", + "kubernetes.io/cluster/": "shared", + } + + label8tID := terraform.Output(t, terraformOptions, "label8t_id") + label8tContextID := terraform.Output(t, terraformOptions, "label8t_context_id") + assert.Equal(t, "Eg-Demo-Blue-Eks-Cluster", label8tID) + assert.Equal(t, label8tID, label8tContextID, "ID and context ID should be equal") + + label8tTags := terraform.OutputMap(t, terraformOptions, "label8t_tags") + label8tContextTags := terraform.OutputMap(t, terraformOptions, "label8t_context_tags") + + assert.Exactly(t, label8tExpectedTags, label8tTags, "generated tags are different from expected") + assert.Exactly(t, label8tTags, label8tContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=upper` and `label_value_case=upper` returns expected values of id, tags, context tags + label8uExpectedTags := map[string]string{ + "ATTRIBUTES": "CLUSTER", + "ENVIRONMENT": "DEMO", + "NAME": "EG-DEMO-BLUE-CLUSTER", + "NAMESPACE": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8uID := terraform.Output(t, terraformOptions, "label8u_id") + label8uContextID := terraform.Output(t, terraformOptions, "label8u_context_id") + assert.Equal(t, "EG-DEMO-BLUE-CLUSTER", label8uID) + assert.Equal(t, label8uID, label8uContextID, "ID and context ID should be equal") + + label8uTags := terraform.OutputMap(t, terraformOptions, "label8u_tags") + label8uContextTags := terraform.OutputMap(t, terraformOptions, "label8u_context_tags") + + assert.Exactly(t, label8uExpectedTags, label8uTags, "generated tags are different from expected") + assert.Exactly(t, label8uTags, label8uContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=none` returns expected values of id, tags, context tags + label8nExpectedTags := map[string]string{ + "Attributes": "eks-ClusteR", + "Environment": "demo", + "Name": "EG-demo-blue-eks-ClusteR", + "Namespace": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8nID := terraform.Output(t, terraformOptions, "label8n_id") + label8nContextID := terraform.Output(t, terraformOptions, "label8n_context_id") + assert.Equal(t, "EG-demo-blue-eks-ClusteR", label8nID) + assert.Equal(t, label8nID, label8nContextID, "ID and context ID should be equal") + + label8nTags := terraform.OutputMap(t, terraformOptions, "label8n_tags") + label8nContextTags := terraform.OutputMap(t, terraformOptions, "label8n_context_tags") + + assert.Exactly(t, label8nExpectedTags, label8nTags, "generated tags are different from expected") + assert.Exactly(t, label8nTags, label8nContextTags, "tags and context tags should be equal") +} diff --git a/.terraform/modules/datadog-integration.artifact.this/test/src/go.mod b/.terraform/modules/datadog-integration.artifact.this/test/src/go.mod new file mode 100755 index 0000000..d866541 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/test/src/go.mod @@ -0,0 +1,9 @@ +module github.com/cloudposse/terraform-null-label + +go 1.14 + +require ( + github.com/gruntwork-io/terratest v0.31.1 + github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 + github.com/stretchr/testify v1.6.1 +) diff --git a/.terraform/modules/datadog-integration.artifact.this/test/src/go.sum b/.terraform/modules/datadog-integration.artifact.this/test/src/go.sum new file mode 100755 index 0000000..b8d46b1 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/test/src/go.sum @@ -0,0 +1,595 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= +github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.5/go.mod h1:foo3aIXRQ90zFve3r0QiDsrjGDUwWhKl0ZOQy1CT14k= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= +github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200109221225-a4f60165b7a3/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= +github.com/gruntwork-io/terratest v0.31.1 h1:MPGe/5pGgJAIZ/hb+0LM1KyJKSi/QyxSkHoP9/CBhJg= +github.com/gruntwork-io/terratest v0.31.1/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= +github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4= +github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= +github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= +k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= +k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= +k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= +k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= +k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= +k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= +k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= +modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/.terraform/modules/datadog-integration.artifact.this/variables.tf b/.terraform/modules/datadog-integration.artifact.this/variables.tf new file mode 100755 index 0000000..40fb268 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/variables.tf @@ -0,0 +1,157 @@ +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} diff --git a/.terraform/modules/datadog-integration.artifact.this/versions.tf b/.terraform/modules/datadog-integration.artifact.this/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog-integration.artifact.this/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog-integration.core_label/LICENSE b/.terraform/modules/datadog-integration.core_label/LICENSE new file mode 100755 index 0000000..c844c70 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017-2020 Cloud Posse, LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/.terraform/modules/datadog-integration.core_label/Makefile b/.terraform/modules/datadog-integration.core_label/Makefile new file mode 100755 index 0000000..97d8087 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/Makefile @@ -0,0 +1,10 @@ +SHELL := /bin/bash + +# List of targets the `readme` target should call before generating the readme +export README_DEPS ?= docs/targets.md docs/terraform.md + +-include $(shell curl -sSL -o .build-harness "https://git.io/build-harness"; echo .build-harness) + +## Lint terraform code +lint: + $(SELF) terraform/install terraform/get-modules terraform/get-plugins terraform/lint terraform/validate diff --git a/.terraform/modules/datadog-integration.core_label/README.md b/.terraform/modules/datadog-integration.core_label/README.md new file mode 100755 index 0000000..32950e4 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/README.md @@ -0,0 +1,938 @@ + +# terraform-null-label [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-null-label.svg)](https://github.com/cloudposse/terraform-null-label/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) + + +[![README Header][readme_header_img]][readme_header_link] + +[![Cloud Posse][logo]](https://cpco.io/homepage) + + + +Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + +This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. +However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). +So if you prefer the term `stage` to `environment` +you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. +- If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. +- If you want the attributes in a different order, you can specify that, too, with the `label_order` list. +- You can set a maximum length for the name, and the module will create a unique name that fits within that length. +- You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. +- The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + +It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. +For example, if you have 10 instances, there should be 10 different labels. +However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + +All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + +**NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. +With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + +- Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. +- Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. +- Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. + + +--- + +This project is part of our comprehensive ["SweetOps"](https://cpco.io/sweetops) approach towards DevOps. +[][share_email] +[][share_googleplus] +[][share_facebook] +[][share_reddit] +[][share_linkedin] +[][share_twitter] + + +[![Terraform Open Source Modules](https://docs.cloudposse.com/images/terraform-open-source-modules.svg)][terraform_modules] + + + +It's 100% Open Source and licensed under the [APACHE2](LICENSE). + + + + + + + +We literally have [*hundreds of terraform modules*][terraform_modules] that are Open Source and well-maintained. Check them out! + + + + + + + +## Security & Compliance [](https://bridgecrew.io/) + +Security scanning is graciously provided by Bridgecrew. Bridgecrew is the leading fully hosted, cloud-native solution providing continuous Terraform security and compliance. + +| Benchmark | Description | +|--------|---------------| +| [![Infrastructure Security](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/general)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=INFRASTRUCTURE+SECURITY) | Infrastructure Security Compliance | +| [![CIS KUBERNETES](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_kubernetes)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+KUBERNETES+V1.5) | Center for Internet Security, KUBERNETES Compliance | +| [![CIS AWS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_aws)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AWS+V1.2) | Center for Internet Security, AWS Compliance | +| [![CIS AZURE](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_azure)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AZURE+V1.1) | Center for Internet Security, AZURE Compliance | +| [![PCI-DSS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/pci)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=PCI-DSS+V3.2) | Payment Card Industry Data Security Standards Compliance | +| [![NIST-800-53](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/nist)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=NIST-800-53) | National Institute of Standards and Technology Compliance | +| [![ISO27001](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/iso)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=ISO27001) | Information Security Management System, ISO/IEC 27001 Compliance | +| [![SOC2](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/soc2)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=SOC2)| Service Organization Control 2 Compliance | +| [![CIS GCP](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_gcp)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+GCP+V1.1) | Center for Internet Security, GCP Compliance | +| [![HIPAA](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/hipaa)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=HIPAA) | Health Insurance Portability and Accountability Compliance | + + + +## Usage + + +**IMPORTANT:** We do not pin modules to versions in our examples because of the +difficulty of keeping the versions in the documentation in sync with the latest released versions. +We highly recommend that in your code you pin the version to the exact version you are +using so that your infrastructure remains stable, and update versions in a +systematic way so that they do not catch you by surprise. + +Also, because of a bug in the Terraform registry ([hashicorp/terraform#21417](https://github.com/hashicorp/terraform/issues/21417)), +the registry shows many of our inputs as required when in fact they are optional. +The table below correctly indicates which inputs are required. + + +### Defaults + +Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. +The context object is a single object that contains all the input values for `terraform-null-label`. +However, each input value can also be specified individually by name as a standard Terraform variable, +and the value of those variables, when set to something other than `null`, will override the value +in the context object. In order to allow chaining of these objects, where the context object input to one +module is transformed and passed to the next module, all the variables default to `null` or empty collections. +The actual default values used when nothing is explicitly set are describe in the documentation below. + +For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, +`terraform-null-label` will actually use the default delimiter `-` (hyphen). + +A non-obvious but intentional consequence of this design is that once a module sets a non-default value, +future modules in the chain cannot reset the value back to the original default. Insted, the new setting +becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, +so once a tag is added, it will remain in the tag set and cannot be removed, although its value can +be overwritten. + +### Simple Example + +```hcl +module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} +``` + +This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` +(you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + +Now reference the label when creating an instance: + +```hcl +resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags +} +``` + +Or define a security group: + +```hcl +resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} +``` + + +### Advanced Example + +Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + +```hcl +module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] +} + +module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] +} +``` + +
+ +### Advanced Example 2 + +Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + +```hcl +tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } +] +``` + +Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + +```hcl +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} +``` + +
+ +### Advanced Example 3 + +See [complete example](./examples/complete) for even more examples. + +This example shows how you can pass the `context` output of one label module to the next label_module, +allowing you to create one label that has the base set of values, and then creating every extra label +as a derivative of that. + +
Click to show + +```hcl +module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} +``` + +This creates label outputs like this: + +```hcl +label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" +} +label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } +} +label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } +} +label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" +} +label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" +} +label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } +} +label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" +} +label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, +] +label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" +} +label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } +} +label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } +} +label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" +} + +``` + +
+ + + + + + + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + + + + +## Share the Love + +Like this project? Please give it a ★ on [our GitHub](https://github.com/cloudposse/terraform-null-label)! (it helps us **a lot**) + +Are you using this project or any of our other projects? Consider [leaving a testimonial][testimonial]. =) + + +## Related Projects + +Check out these related projects. + +- [terraform-terraform-label](https://github.com/cloudposse/terraform-terraform-label) - Terraform Module to define a consistent naming convention by (namespace, environment, stage, name, [attributes]) + + + +## Help + +**Got a question?** We got answers. + +File a GitHub [issue](https://github.com/cloudposse/terraform-null-label/issues), send us an [email][email] or join our [Slack Community][slack]. + +[![README Commercial Support][readme_commercial_support_img]][readme_commercial_support_link] + +## DevOps Accelerator for Startups + + +We are a [**DevOps Accelerator**][commercial_support]. We'll help you build your cloud infrastructure from the ground up so you can own it. Then we'll show you how to operate it and stick around for as long as you need us. + +[![Learn More](https://img.shields.io/badge/learn%20more-success.svg?style=for-the-badge)][commercial_support] + +Work directly with our team of DevOps experts via email, slack, and video conferencing. + +We deliver 10x the value for a fraction of the cost of a full-time engineer. Our track record is not even funny. If you want things done right and you need it done FAST, then we're your best bet. + +- **Reference Architecture.** You'll get everything you need from the ground up built using 100% infrastructure as code. +- **Release Engineering.** You'll have end-to-end CI/CD with unlimited staging environments. +- **Site Reliability Engineering.** You'll have total visibility into your apps and microservices. +- **Security Baseline.** You'll have built-in governance with accountability and audit logs for all changes. +- **GitOps.** You'll be able to operate your infrastructure via Pull Requests. +- **Training.** You'll receive hands-on training so your team can operate what we build. +- **Questions.** You'll have a direct line of communication between our teams via a Shared Slack channel. +- **Troubleshooting.** You'll get help to triage when things aren't working. +- **Code Reviews.** You'll receive constructive feedback on Pull Requests. +- **Bug Fixes.** We'll rapidly work with you to fix any bugs in our projects. + +## Slack Community + +Join our [Open Source Community][slack] on Slack. It's **FREE** for everyone! Our "SweetOps" community is where you get to talk with others who share a similar vision for how to rollout and manage infrastructure. This is the best place to talk shop, ask questions, solicit feedback, and work together as a community to build totally *sweet* infrastructure. + +## Discourse Forums + +Participate in our [Discourse Forums][discourse]. Here you'll find answers to commonly asked questions. Most questions will be related to the enormous number of projects we support on our GitHub. Come here to collaborate on answers, find solutions, and get ideas about the products and services we value. It only takes a minute to get started! Just sign in with SSO using your GitHub account. + +## Newsletter + +Sign up for [our newsletter][newsletter] that covers everything on our technology radar. Receive updates on what we're up to on GitHub as well as awesome new projects we discover. + +## Office Hours + +[Join us every Wednesday via Zoom][office_hours] for our weekly "Lunch & Learn" sessions. It's **FREE** for everyone! + +[![zoom](https://img.cloudposse.com/fit-in/200x200/https://cloudposse.com/wp-content/uploads/2019/08/Powered-by-Zoom.png")][office_hours] + +## Contributing + +### Bug Reports & Feature Requests + +Please use the [issue tracker](https://github.com/cloudposse/terraform-null-label/issues) to report any bugs or file feature requests. + +### Developing + +If you are interested in being a contributor and want to get involved in developing this project or [help out](https://cpco.io/help-out) with our other projects, we would love to hear from you! Shoot us an [email][email]. + +In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. + + 1. **Fork** the repo on GitHub + 2. **Clone** the project to your own machine + 3. **Commit** changes to your own branch + 4. **Push** your work back up to your fork + 5. Submit a **Pull Request** so that we can review your changes + +**NOTE:** Be sure to merge the latest changes from "upstream" before making a pull request! + + +## Copyright + +Copyright © 2017-2021 [Cloud Posse, LLC](https://cpco.io/copyright) + + + +## License + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +See [LICENSE](LICENSE) for full details. + +```text +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +``` + + + + + + + + + +## Trademarks + +All other trademarks referenced herein are the property of their respective owners. + +## About + +This project is maintained and funded by [Cloud Posse, LLC][website]. Like it? Please let us know by [leaving a testimonial][testimonial]! + +[![Cloud Posse][logo]][website] + +We're a [DevOps Professional Services][hire] company based in Los Angeles, CA. We ❤️ [Open Source Software][we_love_open_source]. + +We offer [paid support][commercial_support] on all of our projects. + +Check out [our other projects][github], [follow us on twitter][twitter], [apply for a job][jobs], or [hire us][hire] to help with your cloud strategy and implementation. + + + +### Contributors + + +| [![Erik Osterman][osterman_avatar]][osterman_homepage]
[Erik Osterman][osterman_homepage] | [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]
[Andriy Knysh][aknysh_homepage] | [![Igor Rodionov][goruha_avatar]][goruha_homepage]
[Igor Rodionov][goruha_homepage] | [![Sergey Vasilyev][s2504s_avatar]][s2504s_homepage]
[Sergey Vasilyev][s2504s_homepage] | [![Michael Pereira][MichaelPereira_avatar]][MichaelPereira_homepage]
[Michael Pereira][MichaelPereira_homepage] | [![Jamie Nelson][Jamie-BitFlight_avatar]][Jamie-BitFlight_homepage]
[Jamie Nelson][Jamie-BitFlight_homepage] | [![Vladimir][SweetOps_avatar]][SweetOps_homepage]
[Vladimir][SweetOps_homepage] | [![Daren Desjardins][darend_avatar]][darend_homepage]
[Daren Desjardins][darend_homepage] | [![Maarten van der Hoef][maartenvanderhoef_avatar]][maartenvanderhoef_homepage]
[Maarten van der Hoef][maartenvanderhoef_homepage] | [![Adam Tibbing][tibbing_avatar]][tibbing_homepage]
[Adam Tibbing][tibbing_homepage] | +|---|---|---|---|---|---|---|---|---|---| + + + [osterman_homepage]: https://github.com/osterman + [osterman_avatar]: https://img.cloudposse.com/150x150/https://github.com/osterman.png + [aknysh_homepage]: https://github.com/aknysh + [aknysh_avatar]: https://img.cloudposse.com/150x150/https://github.com/aknysh.png + [goruha_homepage]: https://github.com/goruha + [goruha_avatar]: https://img.cloudposse.com/150x150/https://github.com/goruha.png + [s2504s_homepage]: https://github.com/s2504s + [s2504s_avatar]: https://img.cloudposse.com/150x150/https://github.com/s2504s.png + [MichaelPereira_homepage]: https://github.com/MichaelPereira + [MichaelPereira_avatar]: https://img.cloudposse.com/150x150/https://github.com/MichaelPereira.png + [Jamie-BitFlight_homepage]: https://github.com/Jamie-BitFlight + [Jamie-BitFlight_avatar]: https://img.cloudposse.com/150x150/https://github.com/Jamie-BitFlight.png + [SweetOps_homepage]: https://github.com/SweetOps + [SweetOps_avatar]: https://img.cloudposse.com/150x150/https://github.com/SweetOps.png + [darend_homepage]: https://github.com/darend + [darend_avatar]: https://img.cloudposse.com/150x150/https://github.com/darend.png + [maartenvanderhoef_homepage]: https://github.com/maartenvanderhoef + [maartenvanderhoef_avatar]: https://img.cloudposse.com/150x150/https://github.com/maartenvanderhoef.png + [tibbing_homepage]: https://github.com/tibbing + [tibbing_avatar]: https://img.cloudposse.com/150x150/https://github.com/tibbing.png + +[![README Footer][readme_footer_img]][readme_footer_link] +[![Beacon][beacon]][website] + + [logo]: https://cloudposse.com/logo-300x69.svg + [docs]: https://cpco.io/docs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=docs + [website]: https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=website + [github]: https://cpco.io/github?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=github + [jobs]: https://cpco.io/jobs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=jobs + [hire]: https://cpco.io/hire?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=hire + [slack]: https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=slack + [linkedin]: https://cpco.io/linkedin?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=linkedin + [twitter]: https://cpco.io/twitter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=twitter + [testimonial]: https://cpco.io/leave-testimonial?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=testimonial + [office_hours]: https://cloudposse.com/office-hours?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=office_hours + [newsletter]: https://cpco.io/newsletter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=newsletter + [discourse]: https://ask.sweetops.com/?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=discourse + [email]: https://cpco.io/email?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=email + [commercial_support]: https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=commercial_support + [we_love_open_source]: https://cpco.io/we-love-open-source?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=we_love_open_source + [terraform_modules]: https://cpco.io/terraform-modules?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=terraform_modules + [readme_header_img]: https://cloudposse.com/readme/header/img + [readme_header_link]: https://cloudposse.com/readme/header/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_header_link + [readme_footer_img]: https://cloudposse.com/readme/footer/img + [readme_footer_link]: https://cloudposse.com/readme/footer/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_footer_link + [readme_commercial_support_img]: https://cloudposse.com/readme/commercial-support/img + [readme_commercial_support_link]: https://cloudposse.com/readme/commercial-support/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_commercial_support_link + [share_twitter]: https://twitter.com/intent/tweet/?text=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_linkedin]: https://www.linkedin.com/shareArticle?mini=true&title=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_reddit]: https://reddit.com/submit/?url=https://github.com/cloudposse/terraform-null-label + [share_facebook]: https://facebook.com/sharer/sharer.php?u=https://github.com/cloudposse/terraform-null-label + [share_googleplus]: https://plus.google.com/share?url=https://github.com/cloudposse/terraform-null-label + [share_email]: mailto:?subject=terraform-null-label&body=https://github.com/cloudposse/terraform-null-label + [beacon]: https://ga-beacon.cloudposse.com/UA-76589703-4/cloudposse/terraform-null-label?pixel&cs=github&cm=readme&an=terraform-null-label diff --git a/.terraform/modules/datadog-integration.core_label/README.yaml b/.terraform/modules/datadog-integration.core_label/README.yaml new file mode 100755 index 0000000..42bdb84 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/README.yaml @@ -0,0 +1,618 @@ +name: terraform-null-label +tags: +- aws +- terraform +- terraform-modules +- naming-convention +- name +- namespace +- stage +categories: +- terraform-modules/supported +license: APACHE2 +github_repo: cloudposse/terraform-null-label +badges: +- name: Latest Release + image: https://img.shields.io/github/release/cloudposse/terraform-null-label.svg + url: https://github.com/cloudposse/terraform-null-label/releases/latest +- name: Slack Community + image: https://slack.cloudposse.com/badge.svg + url: https://slack.cloudposse.com +related: +- name: terraform-terraform-label + description: Terraform Module to define a consistent naming convention by (namespace, + environment, stage, name, [attributes]) + url: https://github.com/cloudposse/terraform-terraform-label +description: |- + Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + + This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. + However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). + So if you prefer the term `stage` to `environment` + you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. + - If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. + - If you want the attributes in a different order, you can specify that, too, with the `label_order` list. + - You can set a maximum length for the name, and the module will create a unique name that fits within that length. + - You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. + - The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + + It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. + For example, if you have 10 instances, there should be 10 different labels. + However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + + All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + + **NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. + With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + + - Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. + - Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. + - Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. +usage: |- + ### Defaults + + Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. + The context object is a single object that contains all the input values for `terraform-null-label`. + However, each input value can also be specified individually by name as a standard Terraform variable, + and the value of those variables, when set to something other than `null`, will override the value + in the context object. In order to allow chaining of these objects, where the context object input to one + module is transformed and passed to the next module, all the variables default to `null` or empty collections. + The actual default values used when nothing is explicitly set are describe in the documentation below. + + For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, + `terraform-null-label` will actually use the default delimiter `-` (hyphen). + + A non-obvious but intentional consequence of this design is that once a module sets a non-default value, + future modules in the chain cannot reset the value back to the original default. Insted, the new setting + becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, + so once a tag is added, it will remain in the tag set and cannot be removed, although its value can + be overwritten. + + ### Simple Example + + ```hcl + module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + ``` + + This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` + (you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + + Now reference the label when creating an instance: + + ```hcl + resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags + } + ``` + + Or define a security group: + + ```hcl + resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + } + ``` + + + ### Advanced Example + + Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + + ```hcl + module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] + } + + module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] + } + ``` + +
+ + ### Advanced Example 2 + + Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + + ```hcl + tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } + ] + ``` + + Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + + ```hcl + ################################ + # terraform-null-label example # + ################################ + module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } + } + + ####################### + # Launch template # + ####################### + resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } + } + + ###################### + # Autoscaling group # + ###################### + resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps + } + ``` + +
+ + ### Advanced Example 3 + + See [complete example](./examples/complete) for even more examples. + + This example shows how you can pass the `context` output of one label module to the next label_module, + allowing you to create one label that has the base set of values, and then creating every extra label + as a derivative of that. + +
Click to show + + ```hcl + module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } + } + + module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } + } + + module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } + } + ``` + + This creates label outputs like this: + + ```hcl + label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" + } + label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } + } + label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + } + label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" + } + label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } + } + label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" + } + label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, + ] + label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" + } + label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } + } + label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + } + label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + + ``` + +
+ +include: +- docs/targets.md +- docs/terraform.md +contributors: +- name: Erik Osterman + github: osterman +- name: Andriy Knysh + github: aknysh +- name: Igor Rodionov + github: goruha +- name: Sergey Vasilyev + github: s2504s +- name: Michael Pereira + github: MichaelPereira +- name: Jamie Nelson + github: Jamie-BitFlight +- name: Vladimir + github: SweetOps +- name: Daren Desjardins + github: darend +- name: Maarten van der Hoef + github: maartenvanderhoef +- name: Adam Tibbing + github: tibbing diff --git a/.terraform/modules/datadog-integration.core_label/docs/targets.md b/.terraform/modules/datadog-integration.core_label/docs/targets.md new file mode 100755 index 0000000..3dce8b3 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/docs/targets.md @@ -0,0 +1,12 @@ + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + diff --git a/.terraform/modules/datadog-integration.core_label/docs/terraform.md b/.terraform/modules/datadog-integration.core_label/docs/terraform.md new file mode 100755 index 0000000..d4f48f4 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/docs/terraform.md @@ -0,0 +1,54 @@ + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + diff --git a/.terraform/modules/datadog-integration.core_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars b/.terraform/modules/datadog-integration.core_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars new file mode 100755 index 0000000..f7c725f --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars @@ -0,0 +1,12 @@ +namespace = "eg" +stage = "prod" +name = "app" + +tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" +} + +additional_tag_map = { + propagate_at_launch = "true" +} diff --git a/.terraform/modules/datadog-integration.core_label/examples/autoscalinggroup/context.tf b/.terraform/modules/datadog-integration.core_label/examples/autoscalinggroup/context.tf new file mode 100755 index 0000000..b97f05f --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/autoscalinggroup/context.tf @@ -0,0 +1,216 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog-integration.core_label/examples/autoscalinggroup/main.tf b/.terraform/modules/datadog-integration.core_label/examples/autoscalinggroup/main.tf new file mode 100755 index 0000000..f0d3aa6 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/autoscalinggroup/main.tf @@ -0,0 +1,104 @@ +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + + context = module.this.context +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template { + id = aws_launch_template.default.id + version = "$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} + +################################ +# Provider # +################################ +provider "aws" { + region = "eu-west-1" + + # Make it faster by skipping unneeded checks here + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +############################################################## +# Data sources to get VPC, subnets and security group details +############################################################## +data "aws_vpc" "default" { + default = true +} + +data "aws_subnet_ids" "all" { + vpc_id = data.aws_vpc.default.id +} + +data "aws_security_group" "default" { + vpc_id = data.aws_vpc.default.id + name = "default" +} + +data "aws_ami" "amazon_linux" { + most_recent = true + + owners = ["amazon"] + + filter { + name = "name" + + values = [ + "amzn-ami-hvm-*-x86_64-gp2", + ] + } + + filter { + name = "owner-alias" + + values = [ + "amazon", + ] + } +} + diff --git a/.terraform/modules/datadog-integration.core_label/examples/autoscalinggroup/outputs.tf b/.terraform/modules/datadog-integration.core_label/examples/autoscalinggroup/outputs.tf new file mode 100755 index 0000000..f8fcce5 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/autoscalinggroup/outputs.tf @@ -0,0 +1,12 @@ +# terraform-null-label example used here: Output list of tags applied in each format +output "tags_as_list_of_maps" { + value = module.label.tags_as_list_of_maps +} + +output "tags" { + value = module.label.tags +} + +output "id" { + value = module.label.id +} diff --git a/.terraform/modules/datadog-integration.core_label/examples/autoscalinggroup/versions.tf b/.terraform/modules/datadog-integration.core_label/examples/autoscalinggroup/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/autoscalinggroup/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog-integration.core_label/examples/complete/complete.auto.tfvars b/.terraform/modules/datadog-integration.core_label/examples/complete/complete.auto.tfvars new file mode 100755 index 0000000..e7bc519 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/complete/complete.auto.tfvars @@ -0,0 +1,10 @@ +namespace = "cp" +environment = "uw2" +stage = "prd" +name = "null-label" + +delimiter = "" +id_length_limit = 6 + +label_key_case = "lower" +label_value_case = "upper" diff --git a/.terraform/modules/datadog-integration.core_label/examples/complete/context.tf b/.terraform/modules/datadog-integration.core_label/examples/complete/context.tf new file mode 100755 index 0000000..973d4dc --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/complete/context.tf @@ -0,0 +1,217 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog-integration.core_label/examples/complete/label1.tf b/.terraform/modules/datadog-integration.core_label/examples/complete/label1.tf new file mode 100755 index 0000000..8da353b --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/complete/label1.tf @@ -0,0 +1,42 @@ +module "label1" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label1" { + value = { + id = module.label1.id + name = module.label1.name + namespace = module.label1.namespace + stage = module.label1.stage + attributes = module.label1.attributes + delimiter = module.label1.delimiter + } +} + +output "label1_tags" { + value = module.label1.tags +} + +output "label1_context" { + value = module.label1.context +} + +output "label1_normalized_context" { + value = module.label1.normalized_context +} + + + diff --git a/.terraform/modules/datadog-integration.core_label/examples/complete/label1t1.tf b/.terraform/modules/datadog-integration.core_label/examples/complete/label1t1.tf new file mode 100755 index 0000000..2bcb362 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/complete/label1t1.tf @@ -0,0 +1,18 @@ +module "label1t1" { + source = "../../" + + id_length_limit = 28 + + context = module.label1.context +} + +output "label1t1" { + value = { + id = module.label1t1.id + id_full = module.label1t1.id_full + } +} + +output "label1t1_tags" { + value = module.label1t1.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.core_label/examples/complete/label1t2.tf b/.terraform/modules/datadog-integration.core_label/examples/complete/label1t2.tf new file mode 100755 index 0000000..5df651e --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/complete/label1t2.tf @@ -0,0 +1,18 @@ +module "label1t2" { + source = "../../" + + id_length_limit = 29 + + context = module.label1.context +} + +output "label1t2" { + value = { + id = module.label1t2.id + id_full = module.label1t2.id_full + } +} + +output "label1t2_tags" { + value = module.label1t2.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.core_label/examples/complete/label2.tf b/.terraform/modules/datadog-integration.core_label/examples/complete/label2.tf new file mode 100755 index 0000000..faf7450 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/complete/label2.tf @@ -0,0 +1,42 @@ +module "label2" { + source = "../../" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + regex_replace_chars = "/[^a-zA-Z0-9-+]/" + + additional_tag_map = { + propagate_at_launch = "true" + additional_tag = "yes" + } + + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +output "label2" { + value = { + id = module.label2.id + name = module.label2.name + namespace = module.label2.namespace + stage = module.label2.stage + attributes = module.label2.attributes + delimiter = module.label2.delimiter + } +} + +output "label2_tags" { + value = module.label2.tags +} + +output "label2_tags_as_list_of_maps" { + value = module.label2.tags_as_list_of_maps +} + +output "label2_context" { + value = module.label2.context +} diff --git a/.terraform/modules/datadog-integration.core_label/examples/complete/label3c.tf b/.terraform/modules/datadog-integration.core_label/examples/complete/label3c.tf new file mode 100755 index 0000000..338a636 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/complete/label3c.tf @@ -0,0 +1,36 @@ +module "label3c" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3c" { + value = { + id = module.label3c.id + name = module.label3c.name + namespace = module.label3c.namespace + stage = module.label3c.stage + attributes = module.label3c.attributes + delimiter = module.label3c.delimiter + } +} + +output "label3c_tags" { + value = module.label3c.tags +} + +output "label3c_context" { + value = module.label3c.context +} + +output "label3c_normalized_context" { + value = module.label3c.normalized_context +} diff --git a/.terraform/modules/datadog-integration.core_label/examples/complete/label3n.tf b/.terraform/modules/datadog-integration.core_label/examples/complete/label3n.tf new file mode 100755 index 0000000..ca51282 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/complete/label3n.tf @@ -0,0 +1,36 @@ +module "label3n" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.normalized_context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3n" { + value = { + id = module.label3n.id + name = module.label3n.name + namespace = module.label3n.namespace + stage = module.label3n.stage + attributes = module.label3n.attributes + delimiter = module.label3n.delimiter + } +} + +output "label3n_tags" { + value = module.label3n.tags +} + +output "label3n_context" { + value = module.label3n.context +} + +output "label3n_normalized_context" { + value = module.label3n.normalized_context +} diff --git a/.terraform/modules/datadog-integration.core_label/examples/complete/label4.tf b/.terraform/modules/datadog-integration.core_label/examples/complete/label4.tf new file mode 100755 index 0000000..74e3ca1 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/complete/label4.tf @@ -0,0 +1,34 @@ +module "label4" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + name = "Example Cluster" + attributes = ["big", "fat", "honking", "cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label4" { + value = { + id = module.label4.id + name = module.label4.name + namespace = module.label4.namespace + stage = module.label4.stage + attributes = module.label4.attributes + delimiter = module.label4.delimiter + } +} + +output "label4_tags" { + value = module.label4.tags +} + +output "label4_context" { + value = module.label4.context +} diff --git a/.terraform/modules/datadog-integration.core_label/examples/complete/label5.tf b/.terraform/modules/datadog-integration.core_label/examples/complete/label5.tf new file mode 100755 index 0000000..0f0a76e --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/complete/label5.tf @@ -0,0 +1,33 @@ +module "label5" { + source = "../../" + enabled = false + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + } +} + +output "label5" { + value = { + id = module.label5.id + name = module.label5.name + namespace = module.label5.namespace + stage = module.label5.stage + attributes = module.label5.attributes + delimiter = module.label5.delimiter + } +} + +output "label5_tags" { + value = module.label5.tags +} + +output "label5_context" { + value = module.label5.context +} diff --git a/.terraform/modules/datadog-integration.core_label/examples/complete/label6f.tf b/.terraform/modules/datadog-integration.core_label/examples/complete/label6f.tf new file mode 100755 index 0000000..1ce1bab --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/complete/label6f.tf @@ -0,0 +1,20 @@ +module "label6f" { + source = "../../" + + delimiter = "~" + id_length_limit = 0 + + # Use values from tfvars + context = module.this.context +} + +output "label6f" { + value = { + id = module.label6f.id + id_full = module.label6f.id_full + } +} + +output "label6f_tags" { + value = module.label6f.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.core_label/examples/complete/label6t.tf b/.terraform/modules/datadog-integration.core_label/examples/complete/label6t.tf new file mode 100755 index 0000000..b5d9bc1 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/complete/label6t.tf @@ -0,0 +1,19 @@ +module "label6t" { + source = "../../" + + # Use values from tfvars, + # specifically: complete.auto.tfvars + context = module.this.context +} + +output "label6t" { + value = { + id = module.label6t.id + id_full = module.label6t.id_full + id_length_limit = module.this.context.id_length_limit + } +} + +output "label6t_tags" { + value = module.label6t.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.core_label/examples/complete/label7.tf b/.terraform/modules/datadog-integration.core_label/examples/complete/label7.tf new file mode 100755 index 0000000..bb365d4 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/complete/label7.tf @@ -0,0 +1,44 @@ +module "label7a" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + } +} + +module "label7" { + source = "../../" + + attributes = ["nodegroup"] + + context = module.label7a.context +} + + +output "label7" { + value = { + id = module.label7.id + name = module.label7.name + namespace = module.label7.namespace + stage = module.label7.stage + attributes = module.label7.attributes + delimiter = module.label7.delimiter + } +} + +output "label7_id" { + value = module.label7.id +} + +output "label7_attributes" { + value = module.label7.attributes +} + +output "label7_context" { + value = module.label7.context +} diff --git a/.terraform/modules/datadog-integration.core_label/examples/complete/label8d.tf b/.terraform/modules/datadog-integration.core_label/examples/complete/label8d.tf new file mode 100755 index 0000000..4252419 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/complete/label8d.tf @@ -0,0 +1,44 @@ +module "label8d" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8d_context" { + source = "../../" + + context = module.label8d.context +} + +output "label8d_context_id" { + value = module.label8d_context.id +} + +output "label8d_context_context" { + value = module.label8d_context.context +} + +output "label8d_context_tags" { + value = module.label8d_context.tags +} + +output "label8d_id" { + value = module.label8d.id +} + +output "label8d_context" { + value = module.label8d.context +} + +output "label8d_tags" { + value = module.label8d.tags +} diff --git a/.terraform/modules/datadog-integration.core_label/examples/complete/label8dcd.tf b/.terraform/modules/datadog-integration.core_label/examples/complete/label8dcd.tf new file mode 100755 index 0000000..ccdae21 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/complete/label8dcd.tf @@ -0,0 +1,24 @@ +module "label8dcd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "x" +} + +module "label8dcd_context" { + source = "../../" + + context = module.label8dcd.context +} + +output "label8dcd_context_id" { + value = module.label8dcd_context.id +} + +output "label8dcd_id" { + value = module.label8dcd.id +} diff --git a/.terraform/modules/datadog-integration.core_label/examples/complete/label8dnd.tf b/.terraform/modules/datadog-integration.core_label/examples/complete/label8dnd.tf new file mode 100755 index 0000000..2edb378 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/complete/label8dnd.tf @@ -0,0 +1,24 @@ +module "label8dnd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "" +} + +module "label8dnd_context" { + source = "../../" + + context = module.label8dnd.context +} + +output "label8dnd_context_id" { + value = module.label8dnd_context.id +} + +output "label8dnd_id" { + value = module.label8dnd.id +} diff --git a/.terraform/modules/datadog-integration.core_label/examples/complete/label8l.tf b/.terraform/modules/datadog-integration.core_label/examples/complete/label8l.tf new file mode 100755 index 0000000..7462f9e --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/complete/label8l.tf @@ -0,0 +1,46 @@ +module "label8l" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "lower" + label_value_case = "lower" + + tags = { + "kubernetes.io/cluster/" = "shared" + "upperTEST" = "testUPPER" + } +} + +module "label8l_context" { + source = "../../" + + context = module.label8l.context +} + +output "label8l_context_id" { + value = module.label8l_context.id +} + +output "label8l_context_context" { + value = module.label8l_context.context +} + +output "label8l_context_tags" { + value = module.label8l_context.tags +} + +output "label8l_id" { + value = module.label8l.id +} + +output "label8l_context" { + value = module.label8l.context +} + +output "label8l_tags" { + value = module.label8l.tags +} diff --git a/.terraform/modules/datadog-integration.core_label/examples/complete/label8n.tf b/.terraform/modules/datadog-integration.core_label/examples/complete/label8n.tf new file mode 100755 index 0000000..fd4ad57 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/complete/label8n.tf @@ -0,0 +1,45 @@ +module "label8n" { + source = "../../" + + enabled = true + namespace = "EG" + environment = "demo" + name = "blue" + attributes = ["eks", "ClusteR"] + delimiter = "-" + label_value_case = "none" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8n_context" { + source = "../../" + + context = module.label8n.context +} + +output "label8n_context_id" { + value = module.label8n_context.id +} + +output "label8n_context_context" { + value = module.label8n_context.context +} + +output "label8n_context_tags" { + value = module.label8n_context.tags +} + +output "label8n_id" { + value = module.label8n.id +} + +output "label8n_context" { + value = module.label8n.context +} + +output "label8n_tags" { + value = module.label8n.tags +} diff --git a/.terraform/modules/datadog-integration.core_label/examples/complete/label8t.tf b/.terraform/modules/datadog-integration.core_label/examples/complete/label8t.tf new file mode 100755 index 0000000..cb54c7a --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/complete/label8t.tf @@ -0,0 +1,45 @@ +module "label8t" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["EKS", "cluster"] + delimiter = "-" + label_key_case = "title" + label_value_case = "title" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8t_context" { + source = "../../" + + context = module.label8t.context +} + +output "label8t_context_id" { + value = module.label8t_context.id +} + +output "label8t_context_context" { + value = module.label8t_context.context +} + +output "label8t_context_tags" { + value = module.label8t_context.tags +} + +output "label8t_id" { + value = module.label8t.id +} + +output "label8t_context" { + value = module.label8t.context +} + +output "label8t_tags" { + value = module.label8t.tags +} diff --git a/.terraform/modules/datadog-integration.core_label/examples/complete/label8u.tf b/.terraform/modules/datadog-integration.core_label/examples/complete/label8u.tf new file mode 100755 index 0000000..499535b --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/complete/label8u.tf @@ -0,0 +1,50 @@ +module "label8u" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "upper" + label_value_case = "upper" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8u_context" { + source = "../../" + + context = module.label8u.context +} + +output "label8u_context_id" { + value = module.label8u_context.id +} + +output "label8u_context_context" { + value = module.label8u_context.context +} + +// debug +output "label8u_context_normalized_context" { + value = module.label8u_context.normalized_context +} + +output "label8u_context_tags" { + value = module.label8u_context.tags +} + +output "label8u_id" { + value = module.label8u.id +} + +output "label8u_context" { + value = module.label8u.context +} + +output "label8u_tags" { + value = module.label8u.tags +} diff --git a/.terraform/modules/datadog-integration.core_label/examples/complete/versions.tf b/.terraform/modules/datadog-integration.core_label/examples/complete/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/examples/complete/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog-integration.core_label/exports/context.tf b/.terraform/modules/datadog-integration.core_label/exports/context.tf new file mode 100755 index 0000000..81f99b4 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/exports/context.tf @@ -0,0 +1,202 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog-integration.core_label/main.tf b/.terraform/modules/datadog-integration.core_label/main.tf new file mode 100755 index 0000000..0deda2b --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/main.tf @@ -0,0 +1,146 @@ +locals { + + defaults = { + label_order = ["namespace", "environment", "stage", "name", "attributes"] + regex_replace_chars = "/[^-a-zA-Z0-9]/" + delimiter = "-" + replacement = "" + id_length_limit = 0 + id_hash_length = 5 + label_key_case = "title" + label_value_case = "lower" + } + + # So far, we have decided not to allow overriding replacement or id_hash_length + replacement = local.defaults.replacement + id_hash_length = local.defaults.id_hash_length + + # The values provided by variables supersede the values inherited from the context object, + # except for tags and attributes which are merged. + input = { + # It would be nice to use coalesce here, but we cannot, because it + # is an error for all the arguments to coalesce to be empty. + enabled = var.enabled == null ? var.context.enabled : var.enabled + namespace = var.namespace == null ? var.context.namespace : var.namespace + environment = var.environment == null ? var.context.environment : var.environment + stage = var.stage == null ? var.context.stage : var.stage + name = var.name == null ? var.context.name : var.name + delimiter = var.delimiter == null ? var.context.delimiter : var.delimiter + # modules tack on attributes (passed by var) to the end of the list (passed by context) + attributes = compact(distinct(concat(coalesce(var.context.attributes, []), coalesce(var.attributes, [])))) + tags = merge(var.context.tags, var.tags) + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + label_order = var.label_order == null ? var.context.label_order : var.label_order + regex_replace_chars = var.regex_replace_chars == null ? var.context.regex_replace_chars : var.regex_replace_chars + id_length_limit = var.id_length_limit == null ? var.context.id_length_limit : var.id_length_limit + label_key_case = var.label_key_case == null ? lookup(var.context, "label_key_case", null) : var.label_key_case + label_value_case = var.label_value_case == null ? lookup(var.context, "label_value_case", null) : var.label_value_case + } + + + enabled = local.input.enabled + regex_replace_chars = coalesce(local.input.regex_replace_chars, local.defaults.regex_replace_chars) + + # string_label_names are names of inputs that are strings (not list of strings) used as labels + string_label_names = ["name", "namespace", "environment", "stage"] + normalized_labels = { for k in local.string_label_names : k => + local.input[k] == null ? "" : replace(local.input[k], local.regex_replace_chars, local.replacement) + } + normalized_attributes = compact(distinct([for v in local.input.attributes : replace(v, local.regex_replace_chars, local.replacement)])) + + formatted_labels = { for k in local.string_label_names : k => local.label_value_case == "none" ? local.normalized_labels[k] : + local.label_value_case == "title" ? title(lower(local.normalized_labels[k])) : + local.label_value_case == "upper" ? upper(local.normalized_labels[k]) : lower(local.normalized_labels[k]) + } + + attributes = compact(distinct([ + for v in local.normalized_attributes : (local.label_value_case == "none" ? v : + local.label_value_case == "title" ? title(lower(v)) : + local.label_value_case == "upper" ? upper(v) : lower(v)) + ])) + + name = local.formatted_labels["name"] + namespace = local.formatted_labels["namespace"] + environment = local.formatted_labels["environment"] + stage = local.formatted_labels["stage"] + + delimiter = local.input.delimiter == null ? local.defaults.delimiter : local.input.delimiter + label_order = local.input.label_order == null ? local.defaults.label_order : coalescelist(local.input.label_order, local.defaults.label_order) + id_length_limit = local.input.id_length_limit == null ? local.defaults.id_length_limit : local.input.id_length_limit + label_key_case = local.input.label_key_case == null ? local.defaults.label_key_case : local.input.label_key_case + label_value_case = local.input.label_value_case == null ? local.defaults.label_value_case : local.input.label_value_case + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + + tags = merge(local.generated_tags, local.input.tags) + + tags_as_list_of_maps = flatten([ + for key in keys(local.tags) : merge( + { + key = key + value = local.tags[key] + }, var.additional_tag_map) + ]) + + tags_context = { + # For AWS we need `Name` to be disambiguated since it has a special meaning + name = local.id + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = local.id_context.attributes + } + + generated_tags = { + for l in keys(local.tags_context) : + local.label_key_case == "upper" ? upper(l) : ( + local.label_key_case == "lower" ? lower(l) : title(lower(l)) + ) => local.tags_context[l] if length(local.tags_context[l]) > 0 + } + + id_context = { + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = join(local.delimiter, local.attributes) + } + + labels = [for l in local.label_order : local.id_context[l] if length(local.id_context[l]) > 0] + + id_full = join(local.delimiter, local.labels) + # Create a truncated ID if needed + delimiter_length = length(local.delimiter) + # Calculate length of normal part of ID, leaving room for delimiter and hash + id_truncated_length_limit = local.id_length_limit - (local.id_hash_length + local.delimiter_length) + # Truncate the ID and ensure a single (not double) trailing delimiter + id_truncated = local.id_truncated_length_limit <= 0 ? "" : "${trimsuffix(substr(local.id_full, 0, local.id_truncated_length_limit), local.delimiter)}${local.delimiter}" + # Support usages that disallow numeric characters. Would prefer tr 0-9 q-z but Terraform does not support it. + id_hash_plus = "${md5(local.id_full)}qrstuvwxyz" + id_hash_case = local.label_value_case == "title" ? title(local.id_hash_plus) : local.label_value_case == "upper" ? upper(local.id_hash_plus) : local.label_value_case == "lower" ? lower(local.id_hash_plus) : local.id_hash_plus + id_hash = replace(local.id_hash_case, local.regex_replace_chars, local.replacement) + # Create the short ID by adding a hash to the end of the truncated ID + id_short = substr("${local.id_truncated}${local.id_hash}", 0, local.id_length_limit) + id = local.id_length_limit != 0 && length(local.id_full) > local.id_length_limit ? local.id_short : local.id_full + + + # Context of this label to pass to other label modules + output_context = { + enabled = local.enabled + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + delimiter = local.delimiter + attributes = local.attributes + tags = local.tags + additional_tag_map = local.additional_tag_map + label_order = local.label_order + regex_replace_chars = local.regex_replace_chars + id_length_limit = local.id_length_limit + label_key_case = local.label_key_case + label_value_case = local.label_value_case + } + +} diff --git a/.terraform/modules/datadog-integration.core_label/outputs.tf b/.terraform/modules/datadog-integration.core_label/outputs.tf new file mode 100755 index 0000000..87ad1be --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/outputs.tf @@ -0,0 +1,88 @@ +output "id" { + value = local.enabled ? local.id : "" + description = "Disambiguated ID restricted to `id_length_limit` characters in total" +} + +output "id_full" { + value = local.enabled ? local.id_full : "" + description = "Disambiguated ID not restricted in length" +} + +output "enabled" { + value = local.enabled + description = "True if module is enabled, false otherwise" +} + +output "namespace" { + value = local.enabled ? local.namespace : "" + description = "Normalized namespace" +} + +output "environment" { + value = local.enabled ? local.environment : "" + description = "Normalized environment" +} + +output "name" { + value = local.enabled ? local.name : "" + description = "Normalized name" +} + +output "stage" { + value = local.enabled ? local.stage : "" + description = "Normalized stage" +} + +output "delimiter" { + value = local.enabled ? local.delimiter : "" + description = "Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes`" +} + +output "attributes" { + value = local.enabled ? local.attributes : [] + description = "List of attributes" +} + +output "tags" { + value = local.enabled ? local.tags : {} + description = "Normalized Tag map" +} + +output "additional_tag_map" { + value = local.additional_tag_map + description = "The merged additional_tag_map" +} + +output "label_order" { + value = local.label_order + description = "The naming order actually used to create the ID" +} + +output "regex_replace_chars" { + value = local.regex_replace_chars + description = "The regex_replace_chars actually used to create the ID" +} + +output "id_length_limit" { + value = local.id_length_limit + description = "The id_length_limit actually used to create the ID, with `0` meaning unlimited" +} + +output "tags_as_list_of_maps" { + value = local.tags_as_list_of_maps + description = "Additional tags as a list of maps, which can be used in several AWS resources" +} + +output "normalized_context" { + value = local.output_context + description = "Normalized context of this module" +} + +output "context" { + value = local.input + description = <<-EOT + Merged but otherwise unmodified input to this module, to be used as context input to other modules. + Note: this version will have null values as defaults, not the values actually used as defaults. +EOT +} + diff --git a/.terraform/modules/datadog-integration.core_label/test/Makefile b/.terraform/modules/datadog-integration.core_label/test/Makefile new file mode 100755 index 0000000..ea15d62 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/test/Makefile @@ -0,0 +1,43 @@ +TEST_HARNESS ?= https://github.com/cloudposse/test-harness.git +TEST_HARNESS_BRANCH ?= master +TEST_HARNESS_PATH = $(realpath .test-harness) +BATS_ARGS ?= --tap +BATS_LOG ?= test.log + +# Define a macro to run the tests +define RUN_TESTS +@echo "Running tests in $(1)" +@cd $(1) && bats $(BATS_ARGS) $(addsuffix .bats,$(addprefix $(TEST_HARNESS_PATH)/test/terraform/,$(TESTS))) +endef + +default: all + +-include Makefile.* + +## Provision the test-harnesss +.test-harness: + [ -d $@ ] || git clone --depth=1 -b $(TEST_HARNESS_BRANCH) $(TEST_HARNESS) $@ + +## Initialize the tests +init: .test-harness + +## Install all dependencies (OS specific) +deps:: + @exit 0 + +## Clean up the test harness +clean: + [ "$(TEST_HARNESS_PATH)" == "/" ] || rm -rf $(TEST_HARNESS_PATH) + +## Run all tests +all: module examples/complete + +## Run basic sanity checks against the module itself +module: export TESTS ?= installed lint get-modules module-pinning get-plugins provider-pinning validate terraform-docs input-descriptions output-descriptions +module: deps + $(call RUN_TESTS, ../) + +## Run tests against example +examples/complete: export TESTS ?= installed lint get-modules get-plugins validate init plan apply +examples/complete: deps + $(call RUN_TESTS, ../$@) diff --git a/.terraform/modules/datadog-integration.core_label/test/Makefile.alpine b/.terraform/modules/datadog-integration.core_label/test/Makefile.alpine new file mode 100755 index 0000000..7925b18 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/test/Makefile.alpine @@ -0,0 +1,5 @@ +ifneq (,$(wildcard /sbin/apk)) +## Install all dependencies for alpine +deps:: init + @apk add --update terraform-docs@cloudposse json2hcl@cloudposse +endif diff --git a/.terraform/modules/datadog-integration.core_label/test/src/Makefile b/.terraform/modules/datadog-integration.core_label/test/src/Makefile new file mode 100755 index 0000000..b772822 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/test/src/Makefile @@ -0,0 +1,30 @@ +export TF_CLI_ARGS_init ?= -get-plugins=true +export TERRAFORM_VERSION ?= $(shell curl -s https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r -M '.current_version' | cut -d. -f1-2) + +.DEFAULT_GOAL : all +.PHONY: all + +## Default target +all: test + +.PHONY : init +## Initialize tests +init: + @exit 0 + +.PHONY : test +## Run tests +test: init + go mod download + go test -v -timeout 60m -run TestExamplesComplete + +## Run tests in docker container +docker/test: + docker run --name terratest --rm -it -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e GITHUB_TOKEN \ + -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" \ + -v $(CURDIR)/../../:/module/ cloudposse/test-harness:latest -C /module/test/src test + +.PHONY : clean +## Clean up files +clean: + rm -rf ../../examples/complete/*.tfstate* diff --git a/.terraform/modules/datadog-integration.core_label/test/src/examples_complete_test.go b/.terraform/modules/datadog-integration.core_label/test/src/examples_complete_test.go new file mode 100755 index 0000000..156e293 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/test/src/examples_complete_test.go @@ -0,0 +1,293 @@ +package test + +import ( + "fmt" + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" + "github.com/qdm12/reprint" + "github.com/stretchr/testify/assert" +) + +type NLContext struct { + AdditionalTagMap map[string]string `json:"additional_tag_map"` + Attributes []string `json:"attributes"` + Delimiter interface{} `json:"delimiter"` + Enabled bool `json:"enabled"` + Environment interface{} `json:"environment"` + LabelOrder []string `json:"label_order"` + Name interface{} `json:"name"` + Namespace interface{} `json:"namespace"` + RegexReplaceChars interface{} `json:"regex_replace_chars"` + Stage interface{} `json:"stage"` + Tags map[string]string `json:"tags"` +} + +// Test the Terraform module in examples/complete using Terratest. +func TestExamplesComplete(t *testing.T) { + t.Parallel() + + terraformOptions := &terraform.Options{ + // The path to where our Terraform code is located + TerraformDir: "../../examples/complete", + Upgrade: true, + } + + // At the end of the test, run `terraform destroy` to clean up any resources that were created + defer terraform.Destroy(t, terraformOptions) + + // This will run `terraform init` and `terraform apply` and fail the test if there are any errors + terraform.InitAndApply(t, terraformOptions) + + expectedLabel1Context := NLContext{ + Enabled: true, + Namespace: "CloudPosse", + Environment: "UAT", + Stage: "build", + Name: "Winston Churchroom", + Attributes: []string{"fire", "water", "earth", "air"}, + Delimiter: "-", + LabelOrder: []string{"name", "environment", "stage", "attributes"}, + Tags: map[string]string{ + "City": "Dublin", + "Environment": "Private", + }, + AdditionalTagMap: map[string]string{}, + } + + var expectedLabel1NormalizedContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel1NormalizedContext) + expectedLabel1NormalizedContext.Namespace = "cloudposse" + expectedLabel1NormalizedContext.Environment = "uat" + expectedLabel1NormalizedContext.Name = "winstonchurchroom" + expectedLabel1NormalizedContext.RegexReplaceChars = "/[^-a-zA-Z0-9]/" + expectedLabel1NormalizedContext.Tags = map[string]string{ + "City": "Dublin", + "Environment": "Private", + "Namespace": "cloudposse", + "Stage": "build", + "Name": "winstonchurchroom-uat-build-fire-water-earth-air", + "Attributes": "fire-water-earth-air", + } + + var label1NormalizedContext, label1Context NLContext + // Run `terraform output` to get the value of an output variable + label1 := terraform.OutputMap(t, terraformOptions, "label1") + label1Tags := terraform.OutputMap(t, terraformOptions, "label1_tags") + terraform.OutputStruct(t, terraformOptions, "label1_normalized_context", &label1NormalizedContext) + terraform.OutputStruct(t, terraformOptions, "label1_context", &label1Context) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1["id"]) + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1Tags["Name"]) + assert.Equal(t, "Dublin", label1Tags["City"]) + assert.Equal(t, "Private", label1Tags["Environment"]) + assert.Equal(t, expectedLabel1NormalizedContext, label1NormalizedContext) + assert.Equal(t, expectedLabel1Context, label1Context) + + label1t1 := terraform.OutputMap(t, terraformOptions, "label1t1") + label1t1Tags := terraform.OutputMap(t, terraformOptions, "label1t1_tags") + assert.Equal(t, "winstonchurchroom-uat-6a0b34", label1t1["id"], + "Extra hash character should be added when trailing delimiter is removed") + assert.Equal(t, label1["id"], label1t1["id_full"], "id_full should not be truncated") + assert.Equal(t, label1t1["id"], label1t1Tags["Name"], "Name tag should match ID") + + label1t2 := terraform.OutputMap(t, terraformOptions, "label1t2") + label1t2Tags := terraform.OutputMap(t, terraformOptions, "label1t2_tags") + assert.Equal(t, "winstonchurchroom-uat-b-6a0b3", label1t2["id"]) + assert.Equal(t, label1t2["id"], label1t2Tags["Name"], "Name tag should match ID") + + // Run `terraform output` to get the value of an output variable + label2 := terraform.OutputMap(t, terraformOptions, "label2") + label2Tags := terraform.OutputMap(t, terraformOptions, "label2_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2["id"]) + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2Tags["Name"]) + assert.Equal(t, "London", label2Tags["City"]) + assert.Equal(t, "Public", label2Tags["Environment"]) + + var expectedLabel3cContext, label3cContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel3cContext) + expectedLabel3cContext.Name = "Starfish" + expectedLabel3cContext.Stage = "release" + expectedLabel3cContext.Delimiter = "." + expectedLabel3cContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3cContext.Tags["Eat"] = "Carrot" + expectedLabel3cContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3c := terraform.OutputMap(t, terraformOptions, "label3c") + label3cTags := terraform.OutputMap(t, terraformOptions, "label3c_tags") + terraform.OutputStruct(t, terraformOptions, "label3c_context", &label3cContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3c["id"]) + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3cTags["Name"]) + assert.Equal(t, expectedLabel3cContext, label3cContext) + + var expectedLabel3nContext, label3nContext NLContext + _ = reprint.FromTo(&expectedLabel1NormalizedContext, &expectedLabel3nContext) + expectedLabel3nContext.Name = "Starfish" + expectedLabel3nContext.Stage = "release" + expectedLabel3nContext.Delimiter = "." + expectedLabel3nContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3nContext.Tags["Eat"] = "Carrot" + expectedLabel3nContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3n := terraform.OutputMap(t, terraformOptions, "label3n") + label3nTags := terraform.OutputMap(t, terraformOptions, "label3n_tags") + terraform.OutputStruct(t, terraformOptions, "label3n_context", &label3nContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3n["id"]) + assert.Equal(t, label1Tags["Name"], label3nTags["Name"], + "Tag from label1 normalized context should overwrite label3n generated tag") + assert.Equal(t, expectedLabel3nContext, label3nContext) + + // Run `terraform output` to get the value of an output variable + label4 := terraform.OutputMap(t, terraformOptions, "label4") + label4Tags := terraform.OutputMap(t, terraformOptions, "label4_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4["id"]) + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4Tags["Name"]) + + // Run `terraform output` to get the value of an output variable + label5 := terraform.OutputMap(t, terraformOptions, "label5") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "", label5["id"]) + + label6f := terraform.OutputMap(t, terraformOptions, "label6f") + label6fTags := terraform.OutputMap(t, terraformOptions, "label6f_tags") + // Test of setting var.label_key_case = "lower", var.label_value_case = "upper" + assert.Equal(t, "CP~UW2~PRD~NULL-LABEL", label6f["id_full"]) + assert.Equal(t, label6f["id_full"], label6f["id"], "id should not be truncated") + assert.Equal(t, label6f["id"], label6fTags["name"], "Name tag should match ID") + + label6t := terraform.OutputMap(t, terraformOptions, "label6t") + label6tTags := terraform.OutputMap(t, terraformOptions, "label6t_tags") + assert.Equal(t, "CPUW2PRDNULL-LABEL", label6t["id_full"]) + assert.NotEqual(t, label6t["id_full"], label6t["id"], "id should be truncated") + assert.Equal(t, label6t["id"], label6tTags["name"], "Name tag should match ID") + assert.Equal(t, label6t["id_length_limit"], fmt.Sprintf("%d", len(label6t["id"])), + "Truncated ID length should equal length limit") + + label7 := terraform.OutputMap(t, terraformOptions, "label7") + assert.Equal(t, "eg-demo-blue-cluster-nodegroup", label7["id"], "var.attributes should be appended after context.attributes") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter=""` returns expected value of id, context id + label8dndID := terraform.Output(t, terraformOptions, "label8dnd_id") + label8dndContextID := terraform.Output(t, terraformOptions, "label8dnd_context_id") + assert.Equal(t, "egdemobluecluster", label8dndID) + assert.Equal(t, label8dndID, label8dndContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter="x"` returns expected value of id, context id + label8dcdID := terraform.Output(t, terraformOptions, "label8dcd_id") + label8dcdContextID := terraform.Output(t, terraformOptions, "label8dcd_context_id") + assert.Equal(t, "egxdemoxbluexcluster", label8dcdID) + assert.Equal(t, label8dcdID, label8dcdContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=lower` returns expected values of id, tags, context tags + label8dExpectedTags := map[string]string{ + "Attributes": "cluster", + "Environment": "demo", + "Name": "eg-demo-blue-cluster", + "Namespace": "eg", + "kubernetes.io/cluster/": "shared", + } + + label8dID := terraform.Output(t, terraformOptions, "label8d_id") + label8dContextID := terraform.Output(t, terraformOptions, "label8d_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8dID) + assert.Equal(t, label8dID, label8dContextID, "ID and context ID should be equal") + + label8dTags := terraform.OutputMap(t, terraformOptions, "label8d_tags") + label8dContextTags := terraform.OutputMap(t, terraformOptions, "label8d_context_tags") + + assert.Exactly(t, label8dExpectedTags, label8dTags, "generated tags are different from expected") + assert.Exactly(t, label8dTags, label8dContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=lower` and `label_value_case=lower` returns expected values of id, tags, context tags + label8lExpectedTags := map[string]string{ + "attributes": "cluster", + "environment": "demo", + "name": "eg-demo-blue-cluster", + "namespace": "eg", + "kubernetes.io/cluster/": "shared", + "upperTEST": "testUPPER", + } + + label8lID := terraform.Output(t, terraformOptions, "label8l_id") + label8lContextID := terraform.Output(t, terraformOptions, "label8l_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8lID) + assert.Equal(t, label8lID, label8lContextID, "ID and context ID should be equal") + + label8lTags := terraform.OutputMap(t, terraformOptions, "label8l_tags") + label8lContextTags := terraform.OutputMap(t, terraformOptions, "label8l_context_tags") + + assert.Exactly(t, label8lExpectedTags, label8lTags, "generated tags are different from expected") + assert.Exactly(t, label8lTags, label8lContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=title` returns expected values of id, tags, context tags + label8tExpectedTags := map[string]string{ + "Attributes": "Eks-Cluster", + "Environment": "Demo", + "Name": "Eg-Demo-Blue-Eks-Cluster", + "Namespace": "Eg", + "kubernetes.io/cluster/": "shared", + } + + label8tID := terraform.Output(t, terraformOptions, "label8t_id") + label8tContextID := terraform.Output(t, terraformOptions, "label8t_context_id") + assert.Equal(t, "Eg-Demo-Blue-Eks-Cluster", label8tID) + assert.Equal(t, label8tID, label8tContextID, "ID and context ID should be equal") + + label8tTags := terraform.OutputMap(t, terraformOptions, "label8t_tags") + label8tContextTags := terraform.OutputMap(t, terraformOptions, "label8t_context_tags") + + assert.Exactly(t, label8tExpectedTags, label8tTags, "generated tags are different from expected") + assert.Exactly(t, label8tTags, label8tContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=upper` and `label_value_case=upper` returns expected values of id, tags, context tags + label8uExpectedTags := map[string]string{ + "ATTRIBUTES": "CLUSTER", + "ENVIRONMENT": "DEMO", + "NAME": "EG-DEMO-BLUE-CLUSTER", + "NAMESPACE": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8uID := terraform.Output(t, terraformOptions, "label8u_id") + label8uContextID := terraform.Output(t, terraformOptions, "label8u_context_id") + assert.Equal(t, "EG-DEMO-BLUE-CLUSTER", label8uID) + assert.Equal(t, label8uID, label8uContextID, "ID and context ID should be equal") + + label8uTags := terraform.OutputMap(t, terraformOptions, "label8u_tags") + label8uContextTags := terraform.OutputMap(t, terraformOptions, "label8u_context_tags") + + assert.Exactly(t, label8uExpectedTags, label8uTags, "generated tags are different from expected") + assert.Exactly(t, label8uTags, label8uContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=none` returns expected values of id, tags, context tags + label8nExpectedTags := map[string]string{ + "Attributes": "eks-ClusteR", + "Environment": "demo", + "Name": "EG-demo-blue-eks-ClusteR", + "Namespace": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8nID := terraform.Output(t, terraformOptions, "label8n_id") + label8nContextID := terraform.Output(t, terraformOptions, "label8n_context_id") + assert.Equal(t, "EG-demo-blue-eks-ClusteR", label8nID) + assert.Equal(t, label8nID, label8nContextID, "ID and context ID should be equal") + + label8nTags := terraform.OutputMap(t, terraformOptions, "label8n_tags") + label8nContextTags := terraform.OutputMap(t, terraformOptions, "label8n_context_tags") + + assert.Exactly(t, label8nExpectedTags, label8nTags, "generated tags are different from expected") + assert.Exactly(t, label8nTags, label8nContextTags, "tags and context tags should be equal") +} diff --git a/.terraform/modules/datadog-integration.core_label/test/src/go.mod b/.terraform/modules/datadog-integration.core_label/test/src/go.mod new file mode 100755 index 0000000..d866541 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/test/src/go.mod @@ -0,0 +1,9 @@ +module github.com/cloudposse/terraform-null-label + +go 1.14 + +require ( + github.com/gruntwork-io/terratest v0.31.1 + github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 + github.com/stretchr/testify v1.6.1 +) diff --git a/.terraform/modules/datadog-integration.core_label/test/src/go.sum b/.terraform/modules/datadog-integration.core_label/test/src/go.sum new file mode 100755 index 0000000..b8d46b1 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/test/src/go.sum @@ -0,0 +1,595 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= +github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.5/go.mod h1:foo3aIXRQ90zFve3r0QiDsrjGDUwWhKl0ZOQy1CT14k= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= +github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200109221225-a4f60165b7a3/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= +github.com/gruntwork-io/terratest v0.31.1 h1:MPGe/5pGgJAIZ/hb+0LM1KyJKSi/QyxSkHoP9/CBhJg= +github.com/gruntwork-io/terratest v0.31.1/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= +github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4= +github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= +github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= +k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= +k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= +k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= +k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= +k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= +k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= +k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= +modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/.terraform/modules/datadog-integration.core_label/variables.tf b/.terraform/modules/datadog-integration.core_label/variables.tf new file mode 100755 index 0000000..40fb268 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/variables.tf @@ -0,0 +1,157 @@ +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} diff --git a/.terraform/modules/datadog-integration.core_label/versions.tf b/.terraform/modules/datadog-integration.core_label/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog-integration.core_label/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds b/.terraform/modules/datadog-integration.forwarder_rds new file mode 160000 index 0000000..6f24262 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds @@ -0,0 +1 @@ +Subproject commit 6f24262652a52a055de711cfee0e3dfac5221e0e diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/LICENSE b/.terraform/modules/datadog-integration.forwarder_rds.this/LICENSE new file mode 100755 index 0000000..c844c70 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017-2020 Cloud Posse, LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/Makefile b/.terraform/modules/datadog-integration.forwarder_rds.this/Makefile new file mode 100755 index 0000000..97d8087 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/Makefile @@ -0,0 +1,10 @@ +SHELL := /bin/bash + +# List of targets the `readme` target should call before generating the readme +export README_DEPS ?= docs/targets.md docs/terraform.md + +-include $(shell curl -sSL -o .build-harness "https://git.io/build-harness"; echo .build-harness) + +## Lint terraform code +lint: + $(SELF) terraform/install terraform/get-modules terraform/get-plugins terraform/lint terraform/validate diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/README.md b/.terraform/modules/datadog-integration.forwarder_rds.this/README.md new file mode 100755 index 0000000..32950e4 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/README.md @@ -0,0 +1,938 @@ + +# terraform-null-label [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-null-label.svg)](https://github.com/cloudposse/terraform-null-label/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) + + +[![README Header][readme_header_img]][readme_header_link] + +[![Cloud Posse][logo]](https://cpco.io/homepage) + + + +Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + +This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. +However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). +So if you prefer the term `stage` to `environment` +you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. +- If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. +- If you want the attributes in a different order, you can specify that, too, with the `label_order` list. +- You can set a maximum length for the name, and the module will create a unique name that fits within that length. +- You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. +- The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + +It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. +For example, if you have 10 instances, there should be 10 different labels. +However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + +All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + +**NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. +With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + +- Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. +- Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. +- Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. + + +--- + +This project is part of our comprehensive ["SweetOps"](https://cpco.io/sweetops) approach towards DevOps. +[][share_email] +[][share_googleplus] +[][share_facebook] +[][share_reddit] +[][share_linkedin] +[][share_twitter] + + +[![Terraform Open Source Modules](https://docs.cloudposse.com/images/terraform-open-source-modules.svg)][terraform_modules] + + + +It's 100% Open Source and licensed under the [APACHE2](LICENSE). + + + + + + + +We literally have [*hundreds of terraform modules*][terraform_modules] that are Open Source and well-maintained. Check them out! + + + + + + + +## Security & Compliance [](https://bridgecrew.io/) + +Security scanning is graciously provided by Bridgecrew. Bridgecrew is the leading fully hosted, cloud-native solution providing continuous Terraform security and compliance. + +| Benchmark | Description | +|--------|---------------| +| [![Infrastructure Security](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/general)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=INFRASTRUCTURE+SECURITY) | Infrastructure Security Compliance | +| [![CIS KUBERNETES](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_kubernetes)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+KUBERNETES+V1.5) | Center for Internet Security, KUBERNETES Compliance | +| [![CIS AWS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_aws)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AWS+V1.2) | Center for Internet Security, AWS Compliance | +| [![CIS AZURE](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_azure)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AZURE+V1.1) | Center for Internet Security, AZURE Compliance | +| [![PCI-DSS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/pci)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=PCI-DSS+V3.2) | Payment Card Industry Data Security Standards Compliance | +| [![NIST-800-53](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/nist)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=NIST-800-53) | National Institute of Standards and Technology Compliance | +| [![ISO27001](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/iso)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=ISO27001) | Information Security Management System, ISO/IEC 27001 Compliance | +| [![SOC2](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/soc2)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=SOC2)| Service Organization Control 2 Compliance | +| [![CIS GCP](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_gcp)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+GCP+V1.1) | Center for Internet Security, GCP Compliance | +| [![HIPAA](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/hipaa)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=HIPAA) | Health Insurance Portability and Accountability Compliance | + + + +## Usage + + +**IMPORTANT:** We do not pin modules to versions in our examples because of the +difficulty of keeping the versions in the documentation in sync with the latest released versions. +We highly recommend that in your code you pin the version to the exact version you are +using so that your infrastructure remains stable, and update versions in a +systematic way so that they do not catch you by surprise. + +Also, because of a bug in the Terraform registry ([hashicorp/terraform#21417](https://github.com/hashicorp/terraform/issues/21417)), +the registry shows many of our inputs as required when in fact they are optional. +The table below correctly indicates which inputs are required. + + +### Defaults + +Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. +The context object is a single object that contains all the input values for `terraform-null-label`. +However, each input value can also be specified individually by name as a standard Terraform variable, +and the value of those variables, when set to something other than `null`, will override the value +in the context object. In order to allow chaining of these objects, where the context object input to one +module is transformed and passed to the next module, all the variables default to `null` or empty collections. +The actual default values used when nothing is explicitly set are describe in the documentation below. + +For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, +`terraform-null-label` will actually use the default delimiter `-` (hyphen). + +A non-obvious but intentional consequence of this design is that once a module sets a non-default value, +future modules in the chain cannot reset the value back to the original default. Insted, the new setting +becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, +so once a tag is added, it will remain in the tag set and cannot be removed, although its value can +be overwritten. + +### Simple Example + +```hcl +module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} +``` + +This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` +(you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + +Now reference the label when creating an instance: + +```hcl +resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags +} +``` + +Or define a security group: + +```hcl +resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} +``` + + +### Advanced Example + +Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + +```hcl +module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] +} + +module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] +} +``` + +
+ +### Advanced Example 2 + +Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + +```hcl +tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } +] +``` + +Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + +```hcl +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} +``` + +
+ +### Advanced Example 3 + +See [complete example](./examples/complete) for even more examples. + +This example shows how you can pass the `context` output of one label module to the next label_module, +allowing you to create one label that has the base set of values, and then creating every extra label +as a derivative of that. + +
Click to show + +```hcl +module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} +``` + +This creates label outputs like this: + +```hcl +label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" +} +label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } +} +label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } +} +label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" +} +label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" +} +label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } +} +label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" +} +label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, +] +label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" +} +label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } +} +label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } +} +label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" +} + +``` + +
+ + + + + + + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + + + + +## Share the Love + +Like this project? Please give it a ★ on [our GitHub](https://github.com/cloudposse/terraform-null-label)! (it helps us **a lot**) + +Are you using this project or any of our other projects? Consider [leaving a testimonial][testimonial]. =) + + +## Related Projects + +Check out these related projects. + +- [terraform-terraform-label](https://github.com/cloudposse/terraform-terraform-label) - Terraform Module to define a consistent naming convention by (namespace, environment, stage, name, [attributes]) + + + +## Help + +**Got a question?** We got answers. + +File a GitHub [issue](https://github.com/cloudposse/terraform-null-label/issues), send us an [email][email] or join our [Slack Community][slack]. + +[![README Commercial Support][readme_commercial_support_img]][readme_commercial_support_link] + +## DevOps Accelerator for Startups + + +We are a [**DevOps Accelerator**][commercial_support]. We'll help you build your cloud infrastructure from the ground up so you can own it. Then we'll show you how to operate it and stick around for as long as you need us. + +[![Learn More](https://img.shields.io/badge/learn%20more-success.svg?style=for-the-badge)][commercial_support] + +Work directly with our team of DevOps experts via email, slack, and video conferencing. + +We deliver 10x the value for a fraction of the cost of a full-time engineer. Our track record is not even funny. If you want things done right and you need it done FAST, then we're your best bet. + +- **Reference Architecture.** You'll get everything you need from the ground up built using 100% infrastructure as code. +- **Release Engineering.** You'll have end-to-end CI/CD with unlimited staging environments. +- **Site Reliability Engineering.** You'll have total visibility into your apps and microservices. +- **Security Baseline.** You'll have built-in governance with accountability and audit logs for all changes. +- **GitOps.** You'll be able to operate your infrastructure via Pull Requests. +- **Training.** You'll receive hands-on training so your team can operate what we build. +- **Questions.** You'll have a direct line of communication between our teams via a Shared Slack channel. +- **Troubleshooting.** You'll get help to triage when things aren't working. +- **Code Reviews.** You'll receive constructive feedback on Pull Requests. +- **Bug Fixes.** We'll rapidly work with you to fix any bugs in our projects. + +## Slack Community + +Join our [Open Source Community][slack] on Slack. It's **FREE** for everyone! Our "SweetOps" community is where you get to talk with others who share a similar vision for how to rollout and manage infrastructure. This is the best place to talk shop, ask questions, solicit feedback, and work together as a community to build totally *sweet* infrastructure. + +## Discourse Forums + +Participate in our [Discourse Forums][discourse]. Here you'll find answers to commonly asked questions. Most questions will be related to the enormous number of projects we support on our GitHub. Come here to collaborate on answers, find solutions, and get ideas about the products and services we value. It only takes a minute to get started! Just sign in with SSO using your GitHub account. + +## Newsletter + +Sign up for [our newsletter][newsletter] that covers everything on our technology radar. Receive updates on what we're up to on GitHub as well as awesome new projects we discover. + +## Office Hours + +[Join us every Wednesday via Zoom][office_hours] for our weekly "Lunch & Learn" sessions. It's **FREE** for everyone! + +[![zoom](https://img.cloudposse.com/fit-in/200x200/https://cloudposse.com/wp-content/uploads/2019/08/Powered-by-Zoom.png")][office_hours] + +## Contributing + +### Bug Reports & Feature Requests + +Please use the [issue tracker](https://github.com/cloudposse/terraform-null-label/issues) to report any bugs or file feature requests. + +### Developing + +If you are interested in being a contributor and want to get involved in developing this project or [help out](https://cpco.io/help-out) with our other projects, we would love to hear from you! Shoot us an [email][email]. + +In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. + + 1. **Fork** the repo on GitHub + 2. **Clone** the project to your own machine + 3. **Commit** changes to your own branch + 4. **Push** your work back up to your fork + 5. Submit a **Pull Request** so that we can review your changes + +**NOTE:** Be sure to merge the latest changes from "upstream" before making a pull request! + + +## Copyright + +Copyright © 2017-2021 [Cloud Posse, LLC](https://cpco.io/copyright) + + + +## License + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +See [LICENSE](LICENSE) for full details. + +```text +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +``` + + + + + + + + + +## Trademarks + +All other trademarks referenced herein are the property of their respective owners. + +## About + +This project is maintained and funded by [Cloud Posse, LLC][website]. Like it? Please let us know by [leaving a testimonial][testimonial]! + +[![Cloud Posse][logo]][website] + +We're a [DevOps Professional Services][hire] company based in Los Angeles, CA. We ❤️ [Open Source Software][we_love_open_source]. + +We offer [paid support][commercial_support] on all of our projects. + +Check out [our other projects][github], [follow us on twitter][twitter], [apply for a job][jobs], or [hire us][hire] to help with your cloud strategy and implementation. + + + +### Contributors + + +| [![Erik Osterman][osterman_avatar]][osterman_homepage]
[Erik Osterman][osterman_homepage] | [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]
[Andriy Knysh][aknysh_homepage] | [![Igor Rodionov][goruha_avatar]][goruha_homepage]
[Igor Rodionov][goruha_homepage] | [![Sergey Vasilyev][s2504s_avatar]][s2504s_homepage]
[Sergey Vasilyev][s2504s_homepage] | [![Michael Pereira][MichaelPereira_avatar]][MichaelPereira_homepage]
[Michael Pereira][MichaelPereira_homepage] | [![Jamie Nelson][Jamie-BitFlight_avatar]][Jamie-BitFlight_homepage]
[Jamie Nelson][Jamie-BitFlight_homepage] | [![Vladimir][SweetOps_avatar]][SweetOps_homepage]
[Vladimir][SweetOps_homepage] | [![Daren Desjardins][darend_avatar]][darend_homepage]
[Daren Desjardins][darend_homepage] | [![Maarten van der Hoef][maartenvanderhoef_avatar]][maartenvanderhoef_homepage]
[Maarten van der Hoef][maartenvanderhoef_homepage] | [![Adam Tibbing][tibbing_avatar]][tibbing_homepage]
[Adam Tibbing][tibbing_homepage] | +|---|---|---|---|---|---|---|---|---|---| + + + [osterman_homepage]: https://github.com/osterman + [osterman_avatar]: https://img.cloudposse.com/150x150/https://github.com/osterman.png + [aknysh_homepage]: https://github.com/aknysh + [aknysh_avatar]: https://img.cloudposse.com/150x150/https://github.com/aknysh.png + [goruha_homepage]: https://github.com/goruha + [goruha_avatar]: https://img.cloudposse.com/150x150/https://github.com/goruha.png + [s2504s_homepage]: https://github.com/s2504s + [s2504s_avatar]: https://img.cloudposse.com/150x150/https://github.com/s2504s.png + [MichaelPereira_homepage]: https://github.com/MichaelPereira + [MichaelPereira_avatar]: https://img.cloudposse.com/150x150/https://github.com/MichaelPereira.png + [Jamie-BitFlight_homepage]: https://github.com/Jamie-BitFlight + [Jamie-BitFlight_avatar]: https://img.cloudposse.com/150x150/https://github.com/Jamie-BitFlight.png + [SweetOps_homepage]: https://github.com/SweetOps + [SweetOps_avatar]: https://img.cloudposse.com/150x150/https://github.com/SweetOps.png + [darend_homepage]: https://github.com/darend + [darend_avatar]: https://img.cloudposse.com/150x150/https://github.com/darend.png + [maartenvanderhoef_homepage]: https://github.com/maartenvanderhoef + [maartenvanderhoef_avatar]: https://img.cloudposse.com/150x150/https://github.com/maartenvanderhoef.png + [tibbing_homepage]: https://github.com/tibbing + [tibbing_avatar]: https://img.cloudposse.com/150x150/https://github.com/tibbing.png + +[![README Footer][readme_footer_img]][readme_footer_link] +[![Beacon][beacon]][website] + + [logo]: https://cloudposse.com/logo-300x69.svg + [docs]: https://cpco.io/docs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=docs + [website]: https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=website + [github]: https://cpco.io/github?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=github + [jobs]: https://cpco.io/jobs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=jobs + [hire]: https://cpco.io/hire?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=hire + [slack]: https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=slack + [linkedin]: https://cpco.io/linkedin?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=linkedin + [twitter]: https://cpco.io/twitter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=twitter + [testimonial]: https://cpco.io/leave-testimonial?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=testimonial + [office_hours]: https://cloudposse.com/office-hours?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=office_hours + [newsletter]: https://cpco.io/newsletter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=newsletter + [discourse]: https://ask.sweetops.com/?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=discourse + [email]: https://cpco.io/email?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=email + [commercial_support]: https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=commercial_support + [we_love_open_source]: https://cpco.io/we-love-open-source?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=we_love_open_source + [terraform_modules]: https://cpco.io/terraform-modules?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=terraform_modules + [readme_header_img]: https://cloudposse.com/readme/header/img + [readme_header_link]: https://cloudposse.com/readme/header/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_header_link + [readme_footer_img]: https://cloudposse.com/readme/footer/img + [readme_footer_link]: https://cloudposse.com/readme/footer/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_footer_link + [readme_commercial_support_img]: https://cloudposse.com/readme/commercial-support/img + [readme_commercial_support_link]: https://cloudposse.com/readme/commercial-support/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_commercial_support_link + [share_twitter]: https://twitter.com/intent/tweet/?text=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_linkedin]: https://www.linkedin.com/shareArticle?mini=true&title=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_reddit]: https://reddit.com/submit/?url=https://github.com/cloudposse/terraform-null-label + [share_facebook]: https://facebook.com/sharer/sharer.php?u=https://github.com/cloudposse/terraform-null-label + [share_googleplus]: https://plus.google.com/share?url=https://github.com/cloudposse/terraform-null-label + [share_email]: mailto:?subject=terraform-null-label&body=https://github.com/cloudposse/terraform-null-label + [beacon]: https://ga-beacon.cloudposse.com/UA-76589703-4/cloudposse/terraform-null-label?pixel&cs=github&cm=readme&an=terraform-null-label diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/README.yaml b/.terraform/modules/datadog-integration.forwarder_rds.this/README.yaml new file mode 100755 index 0000000..42bdb84 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/README.yaml @@ -0,0 +1,618 @@ +name: terraform-null-label +tags: +- aws +- terraform +- terraform-modules +- naming-convention +- name +- namespace +- stage +categories: +- terraform-modules/supported +license: APACHE2 +github_repo: cloudposse/terraform-null-label +badges: +- name: Latest Release + image: https://img.shields.io/github/release/cloudposse/terraform-null-label.svg + url: https://github.com/cloudposse/terraform-null-label/releases/latest +- name: Slack Community + image: https://slack.cloudposse.com/badge.svg + url: https://slack.cloudposse.com +related: +- name: terraform-terraform-label + description: Terraform Module to define a consistent naming convention by (namespace, + environment, stage, name, [attributes]) + url: https://github.com/cloudposse/terraform-terraform-label +description: |- + Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + + This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. + However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). + So if you prefer the term `stage` to `environment` + you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. + - If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. + - If you want the attributes in a different order, you can specify that, too, with the `label_order` list. + - You can set a maximum length for the name, and the module will create a unique name that fits within that length. + - You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. + - The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + + It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. + For example, if you have 10 instances, there should be 10 different labels. + However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + + All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + + **NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. + With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + + - Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. + - Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. + - Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. +usage: |- + ### Defaults + + Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. + The context object is a single object that contains all the input values for `terraform-null-label`. + However, each input value can also be specified individually by name as a standard Terraform variable, + and the value of those variables, when set to something other than `null`, will override the value + in the context object. In order to allow chaining of these objects, where the context object input to one + module is transformed and passed to the next module, all the variables default to `null` or empty collections. + The actual default values used when nothing is explicitly set are describe in the documentation below. + + For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, + `terraform-null-label` will actually use the default delimiter `-` (hyphen). + + A non-obvious but intentional consequence of this design is that once a module sets a non-default value, + future modules in the chain cannot reset the value back to the original default. Insted, the new setting + becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, + so once a tag is added, it will remain in the tag set and cannot be removed, although its value can + be overwritten. + + ### Simple Example + + ```hcl + module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + ``` + + This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` + (you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + + Now reference the label when creating an instance: + + ```hcl + resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags + } + ``` + + Or define a security group: + + ```hcl + resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + } + ``` + + + ### Advanced Example + + Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + + ```hcl + module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] + } + + module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] + } + ``` + +
+ + ### Advanced Example 2 + + Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + + ```hcl + tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } + ] + ``` + + Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + + ```hcl + ################################ + # terraform-null-label example # + ################################ + module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } + } + + ####################### + # Launch template # + ####################### + resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } + } + + ###################### + # Autoscaling group # + ###################### + resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps + } + ``` + +
+ + ### Advanced Example 3 + + See [complete example](./examples/complete) for even more examples. + + This example shows how you can pass the `context` output of one label module to the next label_module, + allowing you to create one label that has the base set of values, and then creating every extra label + as a derivative of that. + +
Click to show + + ```hcl + module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } + } + + module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } + } + + module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } + } + ``` + + This creates label outputs like this: + + ```hcl + label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" + } + label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } + } + label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + } + label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" + } + label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } + } + label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" + } + label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, + ] + label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" + } + label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } + } + label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + } + label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + + ``` + +
+ +include: +- docs/targets.md +- docs/terraform.md +contributors: +- name: Erik Osterman + github: osterman +- name: Andriy Knysh + github: aknysh +- name: Igor Rodionov + github: goruha +- name: Sergey Vasilyev + github: s2504s +- name: Michael Pereira + github: MichaelPereira +- name: Jamie Nelson + github: Jamie-BitFlight +- name: Vladimir + github: SweetOps +- name: Daren Desjardins + github: darend +- name: Maarten van der Hoef + github: maartenvanderhoef +- name: Adam Tibbing + github: tibbing diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/docs/targets.md b/.terraform/modules/datadog-integration.forwarder_rds.this/docs/targets.md new file mode 100755 index 0000000..3dce8b3 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/docs/targets.md @@ -0,0 +1,12 @@ + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/docs/terraform.md b/.terraform/modules/datadog-integration.forwarder_rds.this/docs/terraform.md new file mode 100755 index 0000000..d4f48f4 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/docs/terraform.md @@ -0,0 +1,54 @@ + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars new file mode 100755 index 0000000..f7c725f --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars @@ -0,0 +1,12 @@ +namespace = "eg" +stage = "prod" +name = "app" + +tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" +} + +additional_tag_map = { + propagate_at_launch = "true" +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/autoscalinggroup/context.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/autoscalinggroup/context.tf new file mode 100755 index 0000000..b97f05f --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/autoscalinggroup/context.tf @@ -0,0 +1,216 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/autoscalinggroup/main.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/autoscalinggroup/main.tf new file mode 100755 index 0000000..f0d3aa6 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/autoscalinggroup/main.tf @@ -0,0 +1,104 @@ +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + + context = module.this.context +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template { + id = aws_launch_template.default.id + version = "$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} + +################################ +# Provider # +################################ +provider "aws" { + region = "eu-west-1" + + # Make it faster by skipping unneeded checks here + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +############################################################## +# Data sources to get VPC, subnets and security group details +############################################################## +data "aws_vpc" "default" { + default = true +} + +data "aws_subnet_ids" "all" { + vpc_id = data.aws_vpc.default.id +} + +data "aws_security_group" "default" { + vpc_id = data.aws_vpc.default.id + name = "default" +} + +data "aws_ami" "amazon_linux" { + most_recent = true + + owners = ["amazon"] + + filter { + name = "name" + + values = [ + "amzn-ami-hvm-*-x86_64-gp2", + ] + } + + filter { + name = "owner-alias" + + values = [ + "amazon", + ] + } +} + diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/autoscalinggroup/outputs.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/autoscalinggroup/outputs.tf new file mode 100755 index 0000000..f8fcce5 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/autoscalinggroup/outputs.tf @@ -0,0 +1,12 @@ +# terraform-null-label example used here: Output list of tags applied in each format +output "tags_as_list_of_maps" { + value = module.label.tags_as_list_of_maps +} + +output "tags" { + value = module.label.tags +} + +output "id" { + value = module.label.id +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/autoscalinggroup/versions.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/autoscalinggroup/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/autoscalinggroup/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/complete.auto.tfvars b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/complete.auto.tfvars new file mode 100755 index 0000000..e7bc519 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/complete.auto.tfvars @@ -0,0 +1,10 @@ +namespace = "cp" +environment = "uw2" +stage = "prd" +name = "null-label" + +delimiter = "" +id_length_limit = 6 + +label_key_case = "lower" +label_value_case = "upper" diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/context.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/context.tf new file mode 100755 index 0000000..973d4dc --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/context.tf @@ -0,0 +1,217 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label1.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label1.tf new file mode 100755 index 0000000..8da353b --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label1.tf @@ -0,0 +1,42 @@ +module "label1" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label1" { + value = { + id = module.label1.id + name = module.label1.name + namespace = module.label1.namespace + stage = module.label1.stage + attributes = module.label1.attributes + delimiter = module.label1.delimiter + } +} + +output "label1_tags" { + value = module.label1.tags +} + +output "label1_context" { + value = module.label1.context +} + +output "label1_normalized_context" { + value = module.label1.normalized_context +} + + + diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label1t1.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label1t1.tf new file mode 100755 index 0000000..2bcb362 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label1t1.tf @@ -0,0 +1,18 @@ +module "label1t1" { + source = "../../" + + id_length_limit = 28 + + context = module.label1.context +} + +output "label1t1" { + value = { + id = module.label1t1.id + id_full = module.label1t1.id_full + } +} + +output "label1t1_tags" { + value = module.label1t1.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label1t2.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label1t2.tf new file mode 100755 index 0000000..5df651e --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label1t2.tf @@ -0,0 +1,18 @@ +module "label1t2" { + source = "../../" + + id_length_limit = 29 + + context = module.label1.context +} + +output "label1t2" { + value = { + id = module.label1t2.id + id_full = module.label1t2.id_full + } +} + +output "label1t2_tags" { + value = module.label1t2.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label2.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label2.tf new file mode 100755 index 0000000..faf7450 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label2.tf @@ -0,0 +1,42 @@ +module "label2" { + source = "../../" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + regex_replace_chars = "/[^a-zA-Z0-9-+]/" + + additional_tag_map = { + propagate_at_launch = "true" + additional_tag = "yes" + } + + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +output "label2" { + value = { + id = module.label2.id + name = module.label2.name + namespace = module.label2.namespace + stage = module.label2.stage + attributes = module.label2.attributes + delimiter = module.label2.delimiter + } +} + +output "label2_tags" { + value = module.label2.tags +} + +output "label2_tags_as_list_of_maps" { + value = module.label2.tags_as_list_of_maps +} + +output "label2_context" { + value = module.label2.context +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label3c.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label3c.tf new file mode 100755 index 0000000..338a636 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label3c.tf @@ -0,0 +1,36 @@ +module "label3c" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3c" { + value = { + id = module.label3c.id + name = module.label3c.name + namespace = module.label3c.namespace + stage = module.label3c.stage + attributes = module.label3c.attributes + delimiter = module.label3c.delimiter + } +} + +output "label3c_tags" { + value = module.label3c.tags +} + +output "label3c_context" { + value = module.label3c.context +} + +output "label3c_normalized_context" { + value = module.label3c.normalized_context +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label3n.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label3n.tf new file mode 100755 index 0000000..ca51282 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label3n.tf @@ -0,0 +1,36 @@ +module "label3n" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.normalized_context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3n" { + value = { + id = module.label3n.id + name = module.label3n.name + namespace = module.label3n.namespace + stage = module.label3n.stage + attributes = module.label3n.attributes + delimiter = module.label3n.delimiter + } +} + +output "label3n_tags" { + value = module.label3n.tags +} + +output "label3n_context" { + value = module.label3n.context +} + +output "label3n_normalized_context" { + value = module.label3n.normalized_context +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label4.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label4.tf new file mode 100755 index 0000000..74e3ca1 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label4.tf @@ -0,0 +1,34 @@ +module "label4" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + name = "Example Cluster" + attributes = ["big", "fat", "honking", "cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label4" { + value = { + id = module.label4.id + name = module.label4.name + namespace = module.label4.namespace + stage = module.label4.stage + attributes = module.label4.attributes + delimiter = module.label4.delimiter + } +} + +output "label4_tags" { + value = module.label4.tags +} + +output "label4_context" { + value = module.label4.context +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label5.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label5.tf new file mode 100755 index 0000000..0f0a76e --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label5.tf @@ -0,0 +1,33 @@ +module "label5" { + source = "../../" + enabled = false + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + } +} + +output "label5" { + value = { + id = module.label5.id + name = module.label5.name + namespace = module.label5.namespace + stage = module.label5.stage + attributes = module.label5.attributes + delimiter = module.label5.delimiter + } +} + +output "label5_tags" { + value = module.label5.tags +} + +output "label5_context" { + value = module.label5.context +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label6f.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label6f.tf new file mode 100755 index 0000000..1ce1bab --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label6f.tf @@ -0,0 +1,20 @@ +module "label6f" { + source = "../../" + + delimiter = "~" + id_length_limit = 0 + + # Use values from tfvars + context = module.this.context +} + +output "label6f" { + value = { + id = module.label6f.id + id_full = module.label6f.id_full + } +} + +output "label6f_tags" { + value = module.label6f.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label6t.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label6t.tf new file mode 100755 index 0000000..b5d9bc1 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label6t.tf @@ -0,0 +1,19 @@ +module "label6t" { + source = "../../" + + # Use values from tfvars, + # specifically: complete.auto.tfvars + context = module.this.context +} + +output "label6t" { + value = { + id = module.label6t.id + id_full = module.label6t.id_full + id_length_limit = module.this.context.id_length_limit + } +} + +output "label6t_tags" { + value = module.label6t.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label7.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label7.tf new file mode 100755 index 0000000..bb365d4 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label7.tf @@ -0,0 +1,44 @@ +module "label7a" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + } +} + +module "label7" { + source = "../../" + + attributes = ["nodegroup"] + + context = module.label7a.context +} + + +output "label7" { + value = { + id = module.label7.id + name = module.label7.name + namespace = module.label7.namespace + stage = module.label7.stage + attributes = module.label7.attributes + delimiter = module.label7.delimiter + } +} + +output "label7_id" { + value = module.label7.id +} + +output "label7_attributes" { + value = module.label7.attributes +} + +output "label7_context" { + value = module.label7.context +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label8d.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label8d.tf new file mode 100755 index 0000000..4252419 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label8d.tf @@ -0,0 +1,44 @@ +module "label8d" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8d_context" { + source = "../../" + + context = module.label8d.context +} + +output "label8d_context_id" { + value = module.label8d_context.id +} + +output "label8d_context_context" { + value = module.label8d_context.context +} + +output "label8d_context_tags" { + value = module.label8d_context.tags +} + +output "label8d_id" { + value = module.label8d.id +} + +output "label8d_context" { + value = module.label8d.context +} + +output "label8d_tags" { + value = module.label8d.tags +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label8dcd.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label8dcd.tf new file mode 100755 index 0000000..ccdae21 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label8dcd.tf @@ -0,0 +1,24 @@ +module "label8dcd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "x" +} + +module "label8dcd_context" { + source = "../../" + + context = module.label8dcd.context +} + +output "label8dcd_context_id" { + value = module.label8dcd_context.id +} + +output "label8dcd_id" { + value = module.label8dcd.id +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label8dnd.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label8dnd.tf new file mode 100755 index 0000000..2edb378 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label8dnd.tf @@ -0,0 +1,24 @@ +module "label8dnd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "" +} + +module "label8dnd_context" { + source = "../../" + + context = module.label8dnd.context +} + +output "label8dnd_context_id" { + value = module.label8dnd_context.id +} + +output "label8dnd_id" { + value = module.label8dnd.id +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label8l.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label8l.tf new file mode 100755 index 0000000..7462f9e --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label8l.tf @@ -0,0 +1,46 @@ +module "label8l" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "lower" + label_value_case = "lower" + + tags = { + "kubernetes.io/cluster/" = "shared" + "upperTEST" = "testUPPER" + } +} + +module "label8l_context" { + source = "../../" + + context = module.label8l.context +} + +output "label8l_context_id" { + value = module.label8l_context.id +} + +output "label8l_context_context" { + value = module.label8l_context.context +} + +output "label8l_context_tags" { + value = module.label8l_context.tags +} + +output "label8l_id" { + value = module.label8l.id +} + +output "label8l_context" { + value = module.label8l.context +} + +output "label8l_tags" { + value = module.label8l.tags +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label8n.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label8n.tf new file mode 100755 index 0000000..fd4ad57 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label8n.tf @@ -0,0 +1,45 @@ +module "label8n" { + source = "../../" + + enabled = true + namespace = "EG" + environment = "demo" + name = "blue" + attributes = ["eks", "ClusteR"] + delimiter = "-" + label_value_case = "none" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8n_context" { + source = "../../" + + context = module.label8n.context +} + +output "label8n_context_id" { + value = module.label8n_context.id +} + +output "label8n_context_context" { + value = module.label8n_context.context +} + +output "label8n_context_tags" { + value = module.label8n_context.tags +} + +output "label8n_id" { + value = module.label8n.id +} + +output "label8n_context" { + value = module.label8n.context +} + +output "label8n_tags" { + value = module.label8n.tags +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label8t.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label8t.tf new file mode 100755 index 0000000..cb54c7a --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label8t.tf @@ -0,0 +1,45 @@ +module "label8t" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["EKS", "cluster"] + delimiter = "-" + label_key_case = "title" + label_value_case = "title" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8t_context" { + source = "../../" + + context = module.label8t.context +} + +output "label8t_context_id" { + value = module.label8t_context.id +} + +output "label8t_context_context" { + value = module.label8t_context.context +} + +output "label8t_context_tags" { + value = module.label8t_context.tags +} + +output "label8t_id" { + value = module.label8t.id +} + +output "label8t_context" { + value = module.label8t.context +} + +output "label8t_tags" { + value = module.label8t.tags +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label8u.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label8u.tf new file mode 100755 index 0000000..499535b --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/label8u.tf @@ -0,0 +1,50 @@ +module "label8u" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "upper" + label_value_case = "upper" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8u_context" { + source = "../../" + + context = module.label8u.context +} + +output "label8u_context_id" { + value = module.label8u_context.id +} + +output "label8u_context_context" { + value = module.label8u_context.context +} + +// debug +output "label8u_context_normalized_context" { + value = module.label8u_context.normalized_context +} + +output "label8u_context_tags" { + value = module.label8u_context.tags +} + +output "label8u_id" { + value = module.label8u.id +} + +output "label8u_context" { + value = module.label8u.context +} + +output "label8u_tags" { + value = module.label8u.tags +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/versions.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/examples/complete/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/exports/context.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/exports/context.tf new file mode 100755 index 0000000..81f99b4 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/exports/context.tf @@ -0,0 +1,202 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/main.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/main.tf new file mode 100755 index 0000000..0deda2b --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/main.tf @@ -0,0 +1,146 @@ +locals { + + defaults = { + label_order = ["namespace", "environment", "stage", "name", "attributes"] + regex_replace_chars = "/[^-a-zA-Z0-9]/" + delimiter = "-" + replacement = "" + id_length_limit = 0 + id_hash_length = 5 + label_key_case = "title" + label_value_case = "lower" + } + + # So far, we have decided not to allow overriding replacement or id_hash_length + replacement = local.defaults.replacement + id_hash_length = local.defaults.id_hash_length + + # The values provided by variables supersede the values inherited from the context object, + # except for tags and attributes which are merged. + input = { + # It would be nice to use coalesce here, but we cannot, because it + # is an error for all the arguments to coalesce to be empty. + enabled = var.enabled == null ? var.context.enabled : var.enabled + namespace = var.namespace == null ? var.context.namespace : var.namespace + environment = var.environment == null ? var.context.environment : var.environment + stage = var.stage == null ? var.context.stage : var.stage + name = var.name == null ? var.context.name : var.name + delimiter = var.delimiter == null ? var.context.delimiter : var.delimiter + # modules tack on attributes (passed by var) to the end of the list (passed by context) + attributes = compact(distinct(concat(coalesce(var.context.attributes, []), coalesce(var.attributes, [])))) + tags = merge(var.context.tags, var.tags) + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + label_order = var.label_order == null ? var.context.label_order : var.label_order + regex_replace_chars = var.regex_replace_chars == null ? var.context.regex_replace_chars : var.regex_replace_chars + id_length_limit = var.id_length_limit == null ? var.context.id_length_limit : var.id_length_limit + label_key_case = var.label_key_case == null ? lookup(var.context, "label_key_case", null) : var.label_key_case + label_value_case = var.label_value_case == null ? lookup(var.context, "label_value_case", null) : var.label_value_case + } + + + enabled = local.input.enabled + regex_replace_chars = coalesce(local.input.regex_replace_chars, local.defaults.regex_replace_chars) + + # string_label_names are names of inputs that are strings (not list of strings) used as labels + string_label_names = ["name", "namespace", "environment", "stage"] + normalized_labels = { for k in local.string_label_names : k => + local.input[k] == null ? "" : replace(local.input[k], local.regex_replace_chars, local.replacement) + } + normalized_attributes = compact(distinct([for v in local.input.attributes : replace(v, local.regex_replace_chars, local.replacement)])) + + formatted_labels = { for k in local.string_label_names : k => local.label_value_case == "none" ? local.normalized_labels[k] : + local.label_value_case == "title" ? title(lower(local.normalized_labels[k])) : + local.label_value_case == "upper" ? upper(local.normalized_labels[k]) : lower(local.normalized_labels[k]) + } + + attributes = compact(distinct([ + for v in local.normalized_attributes : (local.label_value_case == "none" ? v : + local.label_value_case == "title" ? title(lower(v)) : + local.label_value_case == "upper" ? upper(v) : lower(v)) + ])) + + name = local.formatted_labels["name"] + namespace = local.formatted_labels["namespace"] + environment = local.formatted_labels["environment"] + stage = local.formatted_labels["stage"] + + delimiter = local.input.delimiter == null ? local.defaults.delimiter : local.input.delimiter + label_order = local.input.label_order == null ? local.defaults.label_order : coalescelist(local.input.label_order, local.defaults.label_order) + id_length_limit = local.input.id_length_limit == null ? local.defaults.id_length_limit : local.input.id_length_limit + label_key_case = local.input.label_key_case == null ? local.defaults.label_key_case : local.input.label_key_case + label_value_case = local.input.label_value_case == null ? local.defaults.label_value_case : local.input.label_value_case + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + + tags = merge(local.generated_tags, local.input.tags) + + tags_as_list_of_maps = flatten([ + for key in keys(local.tags) : merge( + { + key = key + value = local.tags[key] + }, var.additional_tag_map) + ]) + + tags_context = { + # For AWS we need `Name` to be disambiguated since it has a special meaning + name = local.id + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = local.id_context.attributes + } + + generated_tags = { + for l in keys(local.tags_context) : + local.label_key_case == "upper" ? upper(l) : ( + local.label_key_case == "lower" ? lower(l) : title(lower(l)) + ) => local.tags_context[l] if length(local.tags_context[l]) > 0 + } + + id_context = { + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = join(local.delimiter, local.attributes) + } + + labels = [for l in local.label_order : local.id_context[l] if length(local.id_context[l]) > 0] + + id_full = join(local.delimiter, local.labels) + # Create a truncated ID if needed + delimiter_length = length(local.delimiter) + # Calculate length of normal part of ID, leaving room for delimiter and hash + id_truncated_length_limit = local.id_length_limit - (local.id_hash_length + local.delimiter_length) + # Truncate the ID and ensure a single (not double) trailing delimiter + id_truncated = local.id_truncated_length_limit <= 0 ? "" : "${trimsuffix(substr(local.id_full, 0, local.id_truncated_length_limit), local.delimiter)}${local.delimiter}" + # Support usages that disallow numeric characters. Would prefer tr 0-9 q-z but Terraform does not support it. + id_hash_plus = "${md5(local.id_full)}qrstuvwxyz" + id_hash_case = local.label_value_case == "title" ? title(local.id_hash_plus) : local.label_value_case == "upper" ? upper(local.id_hash_plus) : local.label_value_case == "lower" ? lower(local.id_hash_plus) : local.id_hash_plus + id_hash = replace(local.id_hash_case, local.regex_replace_chars, local.replacement) + # Create the short ID by adding a hash to the end of the truncated ID + id_short = substr("${local.id_truncated}${local.id_hash}", 0, local.id_length_limit) + id = local.id_length_limit != 0 && length(local.id_full) > local.id_length_limit ? local.id_short : local.id_full + + + # Context of this label to pass to other label modules + output_context = { + enabled = local.enabled + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + delimiter = local.delimiter + attributes = local.attributes + tags = local.tags + additional_tag_map = local.additional_tag_map + label_order = local.label_order + regex_replace_chars = local.regex_replace_chars + id_length_limit = local.id_length_limit + label_key_case = local.label_key_case + label_value_case = local.label_value_case + } + +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/outputs.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/outputs.tf new file mode 100755 index 0000000..87ad1be --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/outputs.tf @@ -0,0 +1,88 @@ +output "id" { + value = local.enabled ? local.id : "" + description = "Disambiguated ID restricted to `id_length_limit` characters in total" +} + +output "id_full" { + value = local.enabled ? local.id_full : "" + description = "Disambiguated ID not restricted in length" +} + +output "enabled" { + value = local.enabled + description = "True if module is enabled, false otherwise" +} + +output "namespace" { + value = local.enabled ? local.namespace : "" + description = "Normalized namespace" +} + +output "environment" { + value = local.enabled ? local.environment : "" + description = "Normalized environment" +} + +output "name" { + value = local.enabled ? local.name : "" + description = "Normalized name" +} + +output "stage" { + value = local.enabled ? local.stage : "" + description = "Normalized stage" +} + +output "delimiter" { + value = local.enabled ? local.delimiter : "" + description = "Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes`" +} + +output "attributes" { + value = local.enabled ? local.attributes : [] + description = "List of attributes" +} + +output "tags" { + value = local.enabled ? local.tags : {} + description = "Normalized Tag map" +} + +output "additional_tag_map" { + value = local.additional_tag_map + description = "The merged additional_tag_map" +} + +output "label_order" { + value = local.label_order + description = "The naming order actually used to create the ID" +} + +output "regex_replace_chars" { + value = local.regex_replace_chars + description = "The regex_replace_chars actually used to create the ID" +} + +output "id_length_limit" { + value = local.id_length_limit + description = "The id_length_limit actually used to create the ID, with `0` meaning unlimited" +} + +output "tags_as_list_of_maps" { + value = local.tags_as_list_of_maps + description = "Additional tags as a list of maps, which can be used in several AWS resources" +} + +output "normalized_context" { + value = local.output_context + description = "Normalized context of this module" +} + +output "context" { + value = local.input + description = <<-EOT + Merged but otherwise unmodified input to this module, to be used as context input to other modules. + Note: this version will have null values as defaults, not the values actually used as defaults. +EOT +} + diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/test/Makefile b/.terraform/modules/datadog-integration.forwarder_rds.this/test/Makefile new file mode 100755 index 0000000..ea15d62 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/test/Makefile @@ -0,0 +1,43 @@ +TEST_HARNESS ?= https://github.com/cloudposse/test-harness.git +TEST_HARNESS_BRANCH ?= master +TEST_HARNESS_PATH = $(realpath .test-harness) +BATS_ARGS ?= --tap +BATS_LOG ?= test.log + +# Define a macro to run the tests +define RUN_TESTS +@echo "Running tests in $(1)" +@cd $(1) && bats $(BATS_ARGS) $(addsuffix .bats,$(addprefix $(TEST_HARNESS_PATH)/test/terraform/,$(TESTS))) +endef + +default: all + +-include Makefile.* + +## Provision the test-harnesss +.test-harness: + [ -d $@ ] || git clone --depth=1 -b $(TEST_HARNESS_BRANCH) $(TEST_HARNESS) $@ + +## Initialize the tests +init: .test-harness + +## Install all dependencies (OS specific) +deps:: + @exit 0 + +## Clean up the test harness +clean: + [ "$(TEST_HARNESS_PATH)" == "/" ] || rm -rf $(TEST_HARNESS_PATH) + +## Run all tests +all: module examples/complete + +## Run basic sanity checks against the module itself +module: export TESTS ?= installed lint get-modules module-pinning get-plugins provider-pinning validate terraform-docs input-descriptions output-descriptions +module: deps + $(call RUN_TESTS, ../) + +## Run tests against example +examples/complete: export TESTS ?= installed lint get-modules get-plugins validate init plan apply +examples/complete: deps + $(call RUN_TESTS, ../$@) diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/test/Makefile.alpine b/.terraform/modules/datadog-integration.forwarder_rds.this/test/Makefile.alpine new file mode 100755 index 0000000..7925b18 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/test/Makefile.alpine @@ -0,0 +1,5 @@ +ifneq (,$(wildcard /sbin/apk)) +## Install all dependencies for alpine +deps:: init + @apk add --update terraform-docs@cloudposse json2hcl@cloudposse +endif diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/test/src/Makefile b/.terraform/modules/datadog-integration.forwarder_rds.this/test/src/Makefile new file mode 100755 index 0000000..b772822 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/test/src/Makefile @@ -0,0 +1,30 @@ +export TF_CLI_ARGS_init ?= -get-plugins=true +export TERRAFORM_VERSION ?= $(shell curl -s https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r -M '.current_version' | cut -d. -f1-2) + +.DEFAULT_GOAL : all +.PHONY: all + +## Default target +all: test + +.PHONY : init +## Initialize tests +init: + @exit 0 + +.PHONY : test +## Run tests +test: init + go mod download + go test -v -timeout 60m -run TestExamplesComplete + +## Run tests in docker container +docker/test: + docker run --name terratest --rm -it -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e GITHUB_TOKEN \ + -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" \ + -v $(CURDIR)/../../:/module/ cloudposse/test-harness:latest -C /module/test/src test + +.PHONY : clean +## Clean up files +clean: + rm -rf ../../examples/complete/*.tfstate* diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/test/src/examples_complete_test.go b/.terraform/modules/datadog-integration.forwarder_rds.this/test/src/examples_complete_test.go new file mode 100755 index 0000000..156e293 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/test/src/examples_complete_test.go @@ -0,0 +1,293 @@ +package test + +import ( + "fmt" + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" + "github.com/qdm12/reprint" + "github.com/stretchr/testify/assert" +) + +type NLContext struct { + AdditionalTagMap map[string]string `json:"additional_tag_map"` + Attributes []string `json:"attributes"` + Delimiter interface{} `json:"delimiter"` + Enabled bool `json:"enabled"` + Environment interface{} `json:"environment"` + LabelOrder []string `json:"label_order"` + Name interface{} `json:"name"` + Namespace interface{} `json:"namespace"` + RegexReplaceChars interface{} `json:"regex_replace_chars"` + Stage interface{} `json:"stage"` + Tags map[string]string `json:"tags"` +} + +// Test the Terraform module in examples/complete using Terratest. +func TestExamplesComplete(t *testing.T) { + t.Parallel() + + terraformOptions := &terraform.Options{ + // The path to where our Terraform code is located + TerraformDir: "../../examples/complete", + Upgrade: true, + } + + // At the end of the test, run `terraform destroy` to clean up any resources that were created + defer terraform.Destroy(t, terraformOptions) + + // This will run `terraform init` and `terraform apply` and fail the test if there are any errors + terraform.InitAndApply(t, terraformOptions) + + expectedLabel1Context := NLContext{ + Enabled: true, + Namespace: "CloudPosse", + Environment: "UAT", + Stage: "build", + Name: "Winston Churchroom", + Attributes: []string{"fire", "water", "earth", "air"}, + Delimiter: "-", + LabelOrder: []string{"name", "environment", "stage", "attributes"}, + Tags: map[string]string{ + "City": "Dublin", + "Environment": "Private", + }, + AdditionalTagMap: map[string]string{}, + } + + var expectedLabel1NormalizedContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel1NormalizedContext) + expectedLabel1NormalizedContext.Namespace = "cloudposse" + expectedLabel1NormalizedContext.Environment = "uat" + expectedLabel1NormalizedContext.Name = "winstonchurchroom" + expectedLabel1NormalizedContext.RegexReplaceChars = "/[^-a-zA-Z0-9]/" + expectedLabel1NormalizedContext.Tags = map[string]string{ + "City": "Dublin", + "Environment": "Private", + "Namespace": "cloudposse", + "Stage": "build", + "Name": "winstonchurchroom-uat-build-fire-water-earth-air", + "Attributes": "fire-water-earth-air", + } + + var label1NormalizedContext, label1Context NLContext + // Run `terraform output` to get the value of an output variable + label1 := terraform.OutputMap(t, terraformOptions, "label1") + label1Tags := terraform.OutputMap(t, terraformOptions, "label1_tags") + terraform.OutputStruct(t, terraformOptions, "label1_normalized_context", &label1NormalizedContext) + terraform.OutputStruct(t, terraformOptions, "label1_context", &label1Context) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1["id"]) + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1Tags["Name"]) + assert.Equal(t, "Dublin", label1Tags["City"]) + assert.Equal(t, "Private", label1Tags["Environment"]) + assert.Equal(t, expectedLabel1NormalizedContext, label1NormalizedContext) + assert.Equal(t, expectedLabel1Context, label1Context) + + label1t1 := terraform.OutputMap(t, terraformOptions, "label1t1") + label1t1Tags := terraform.OutputMap(t, terraformOptions, "label1t1_tags") + assert.Equal(t, "winstonchurchroom-uat-6a0b34", label1t1["id"], + "Extra hash character should be added when trailing delimiter is removed") + assert.Equal(t, label1["id"], label1t1["id_full"], "id_full should not be truncated") + assert.Equal(t, label1t1["id"], label1t1Tags["Name"], "Name tag should match ID") + + label1t2 := terraform.OutputMap(t, terraformOptions, "label1t2") + label1t2Tags := terraform.OutputMap(t, terraformOptions, "label1t2_tags") + assert.Equal(t, "winstonchurchroom-uat-b-6a0b3", label1t2["id"]) + assert.Equal(t, label1t2["id"], label1t2Tags["Name"], "Name tag should match ID") + + // Run `terraform output` to get the value of an output variable + label2 := terraform.OutputMap(t, terraformOptions, "label2") + label2Tags := terraform.OutputMap(t, terraformOptions, "label2_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2["id"]) + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2Tags["Name"]) + assert.Equal(t, "London", label2Tags["City"]) + assert.Equal(t, "Public", label2Tags["Environment"]) + + var expectedLabel3cContext, label3cContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel3cContext) + expectedLabel3cContext.Name = "Starfish" + expectedLabel3cContext.Stage = "release" + expectedLabel3cContext.Delimiter = "." + expectedLabel3cContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3cContext.Tags["Eat"] = "Carrot" + expectedLabel3cContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3c := terraform.OutputMap(t, terraformOptions, "label3c") + label3cTags := terraform.OutputMap(t, terraformOptions, "label3c_tags") + terraform.OutputStruct(t, terraformOptions, "label3c_context", &label3cContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3c["id"]) + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3cTags["Name"]) + assert.Equal(t, expectedLabel3cContext, label3cContext) + + var expectedLabel3nContext, label3nContext NLContext + _ = reprint.FromTo(&expectedLabel1NormalizedContext, &expectedLabel3nContext) + expectedLabel3nContext.Name = "Starfish" + expectedLabel3nContext.Stage = "release" + expectedLabel3nContext.Delimiter = "." + expectedLabel3nContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3nContext.Tags["Eat"] = "Carrot" + expectedLabel3nContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3n := terraform.OutputMap(t, terraformOptions, "label3n") + label3nTags := terraform.OutputMap(t, terraformOptions, "label3n_tags") + terraform.OutputStruct(t, terraformOptions, "label3n_context", &label3nContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3n["id"]) + assert.Equal(t, label1Tags["Name"], label3nTags["Name"], + "Tag from label1 normalized context should overwrite label3n generated tag") + assert.Equal(t, expectedLabel3nContext, label3nContext) + + // Run `terraform output` to get the value of an output variable + label4 := terraform.OutputMap(t, terraformOptions, "label4") + label4Tags := terraform.OutputMap(t, terraformOptions, "label4_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4["id"]) + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4Tags["Name"]) + + // Run `terraform output` to get the value of an output variable + label5 := terraform.OutputMap(t, terraformOptions, "label5") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "", label5["id"]) + + label6f := terraform.OutputMap(t, terraformOptions, "label6f") + label6fTags := terraform.OutputMap(t, terraformOptions, "label6f_tags") + // Test of setting var.label_key_case = "lower", var.label_value_case = "upper" + assert.Equal(t, "CP~UW2~PRD~NULL-LABEL", label6f["id_full"]) + assert.Equal(t, label6f["id_full"], label6f["id"], "id should not be truncated") + assert.Equal(t, label6f["id"], label6fTags["name"], "Name tag should match ID") + + label6t := terraform.OutputMap(t, terraformOptions, "label6t") + label6tTags := terraform.OutputMap(t, terraformOptions, "label6t_tags") + assert.Equal(t, "CPUW2PRDNULL-LABEL", label6t["id_full"]) + assert.NotEqual(t, label6t["id_full"], label6t["id"], "id should be truncated") + assert.Equal(t, label6t["id"], label6tTags["name"], "Name tag should match ID") + assert.Equal(t, label6t["id_length_limit"], fmt.Sprintf("%d", len(label6t["id"])), + "Truncated ID length should equal length limit") + + label7 := terraform.OutputMap(t, terraformOptions, "label7") + assert.Equal(t, "eg-demo-blue-cluster-nodegroup", label7["id"], "var.attributes should be appended after context.attributes") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter=""` returns expected value of id, context id + label8dndID := terraform.Output(t, terraformOptions, "label8dnd_id") + label8dndContextID := terraform.Output(t, terraformOptions, "label8dnd_context_id") + assert.Equal(t, "egdemobluecluster", label8dndID) + assert.Equal(t, label8dndID, label8dndContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter="x"` returns expected value of id, context id + label8dcdID := terraform.Output(t, terraformOptions, "label8dcd_id") + label8dcdContextID := terraform.Output(t, terraformOptions, "label8dcd_context_id") + assert.Equal(t, "egxdemoxbluexcluster", label8dcdID) + assert.Equal(t, label8dcdID, label8dcdContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=lower` returns expected values of id, tags, context tags + label8dExpectedTags := map[string]string{ + "Attributes": "cluster", + "Environment": "demo", + "Name": "eg-demo-blue-cluster", + "Namespace": "eg", + "kubernetes.io/cluster/": "shared", + } + + label8dID := terraform.Output(t, terraformOptions, "label8d_id") + label8dContextID := terraform.Output(t, terraformOptions, "label8d_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8dID) + assert.Equal(t, label8dID, label8dContextID, "ID and context ID should be equal") + + label8dTags := terraform.OutputMap(t, terraformOptions, "label8d_tags") + label8dContextTags := terraform.OutputMap(t, terraformOptions, "label8d_context_tags") + + assert.Exactly(t, label8dExpectedTags, label8dTags, "generated tags are different from expected") + assert.Exactly(t, label8dTags, label8dContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=lower` and `label_value_case=lower` returns expected values of id, tags, context tags + label8lExpectedTags := map[string]string{ + "attributes": "cluster", + "environment": "demo", + "name": "eg-demo-blue-cluster", + "namespace": "eg", + "kubernetes.io/cluster/": "shared", + "upperTEST": "testUPPER", + } + + label8lID := terraform.Output(t, terraformOptions, "label8l_id") + label8lContextID := terraform.Output(t, terraformOptions, "label8l_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8lID) + assert.Equal(t, label8lID, label8lContextID, "ID and context ID should be equal") + + label8lTags := terraform.OutputMap(t, terraformOptions, "label8l_tags") + label8lContextTags := terraform.OutputMap(t, terraformOptions, "label8l_context_tags") + + assert.Exactly(t, label8lExpectedTags, label8lTags, "generated tags are different from expected") + assert.Exactly(t, label8lTags, label8lContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=title` returns expected values of id, tags, context tags + label8tExpectedTags := map[string]string{ + "Attributes": "Eks-Cluster", + "Environment": "Demo", + "Name": "Eg-Demo-Blue-Eks-Cluster", + "Namespace": "Eg", + "kubernetes.io/cluster/": "shared", + } + + label8tID := terraform.Output(t, terraformOptions, "label8t_id") + label8tContextID := terraform.Output(t, terraformOptions, "label8t_context_id") + assert.Equal(t, "Eg-Demo-Blue-Eks-Cluster", label8tID) + assert.Equal(t, label8tID, label8tContextID, "ID and context ID should be equal") + + label8tTags := terraform.OutputMap(t, terraformOptions, "label8t_tags") + label8tContextTags := terraform.OutputMap(t, terraformOptions, "label8t_context_tags") + + assert.Exactly(t, label8tExpectedTags, label8tTags, "generated tags are different from expected") + assert.Exactly(t, label8tTags, label8tContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=upper` and `label_value_case=upper` returns expected values of id, tags, context tags + label8uExpectedTags := map[string]string{ + "ATTRIBUTES": "CLUSTER", + "ENVIRONMENT": "DEMO", + "NAME": "EG-DEMO-BLUE-CLUSTER", + "NAMESPACE": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8uID := terraform.Output(t, terraformOptions, "label8u_id") + label8uContextID := terraform.Output(t, terraformOptions, "label8u_context_id") + assert.Equal(t, "EG-DEMO-BLUE-CLUSTER", label8uID) + assert.Equal(t, label8uID, label8uContextID, "ID and context ID should be equal") + + label8uTags := terraform.OutputMap(t, terraformOptions, "label8u_tags") + label8uContextTags := terraform.OutputMap(t, terraformOptions, "label8u_context_tags") + + assert.Exactly(t, label8uExpectedTags, label8uTags, "generated tags are different from expected") + assert.Exactly(t, label8uTags, label8uContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=none` returns expected values of id, tags, context tags + label8nExpectedTags := map[string]string{ + "Attributes": "eks-ClusteR", + "Environment": "demo", + "Name": "EG-demo-blue-eks-ClusteR", + "Namespace": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8nID := terraform.Output(t, terraformOptions, "label8n_id") + label8nContextID := terraform.Output(t, terraformOptions, "label8n_context_id") + assert.Equal(t, "EG-demo-blue-eks-ClusteR", label8nID) + assert.Equal(t, label8nID, label8nContextID, "ID and context ID should be equal") + + label8nTags := terraform.OutputMap(t, terraformOptions, "label8n_tags") + label8nContextTags := terraform.OutputMap(t, terraformOptions, "label8n_context_tags") + + assert.Exactly(t, label8nExpectedTags, label8nTags, "generated tags are different from expected") + assert.Exactly(t, label8nTags, label8nContextTags, "tags and context tags should be equal") +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/test/src/go.mod b/.terraform/modules/datadog-integration.forwarder_rds.this/test/src/go.mod new file mode 100755 index 0000000..d866541 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/test/src/go.mod @@ -0,0 +1,9 @@ +module github.com/cloudposse/terraform-null-label + +go 1.14 + +require ( + github.com/gruntwork-io/terratest v0.31.1 + github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 + github.com/stretchr/testify v1.6.1 +) diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/test/src/go.sum b/.terraform/modules/datadog-integration.forwarder_rds.this/test/src/go.sum new file mode 100755 index 0000000..b8d46b1 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/test/src/go.sum @@ -0,0 +1,595 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= +github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.5/go.mod h1:foo3aIXRQ90zFve3r0QiDsrjGDUwWhKl0ZOQy1CT14k= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= +github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200109221225-a4f60165b7a3/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= +github.com/gruntwork-io/terratest v0.31.1 h1:MPGe/5pGgJAIZ/hb+0LM1KyJKSi/QyxSkHoP9/CBhJg= +github.com/gruntwork-io/terratest v0.31.1/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= +github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4= +github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= +github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= +k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= +k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= +k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= +k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= +k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= +k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= +k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= +modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/variables.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/variables.tf new file mode 100755 index 0000000..40fb268 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/variables.tf @@ -0,0 +1,157 @@ +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds.this/versions.tf b/.terraform/modules/datadog-integration.forwarder_rds.this/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds.this/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/LICENSE b/.terraform/modules/datadog-integration.forwarder_rds_label/LICENSE new file mode 100755 index 0000000..c844c70 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017-2020 Cloud Posse, LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/Makefile b/.terraform/modules/datadog-integration.forwarder_rds_label/Makefile new file mode 100755 index 0000000..97d8087 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/Makefile @@ -0,0 +1,10 @@ +SHELL := /bin/bash + +# List of targets the `readme` target should call before generating the readme +export README_DEPS ?= docs/targets.md docs/terraform.md + +-include $(shell curl -sSL -o .build-harness "https://git.io/build-harness"; echo .build-harness) + +## Lint terraform code +lint: + $(SELF) terraform/install terraform/get-modules terraform/get-plugins terraform/lint terraform/validate diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/README.md b/.terraform/modules/datadog-integration.forwarder_rds_label/README.md new file mode 100755 index 0000000..32950e4 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/README.md @@ -0,0 +1,938 @@ + +# terraform-null-label [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-null-label.svg)](https://github.com/cloudposse/terraform-null-label/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) + + +[![README Header][readme_header_img]][readme_header_link] + +[![Cloud Posse][logo]](https://cpco.io/homepage) + + + +Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + +This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. +However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). +So if you prefer the term `stage` to `environment` +you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. +- If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. +- If you want the attributes in a different order, you can specify that, too, with the `label_order` list. +- You can set a maximum length for the name, and the module will create a unique name that fits within that length. +- You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. +- The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + +It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. +For example, if you have 10 instances, there should be 10 different labels. +However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + +All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + +**NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. +With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + +- Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. +- Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. +- Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. + + +--- + +This project is part of our comprehensive ["SweetOps"](https://cpco.io/sweetops) approach towards DevOps. +[][share_email] +[][share_googleplus] +[][share_facebook] +[][share_reddit] +[][share_linkedin] +[][share_twitter] + + +[![Terraform Open Source Modules](https://docs.cloudposse.com/images/terraform-open-source-modules.svg)][terraform_modules] + + + +It's 100% Open Source and licensed under the [APACHE2](LICENSE). + + + + + + + +We literally have [*hundreds of terraform modules*][terraform_modules] that are Open Source and well-maintained. Check them out! + + + + + + + +## Security & Compliance [](https://bridgecrew.io/) + +Security scanning is graciously provided by Bridgecrew. Bridgecrew is the leading fully hosted, cloud-native solution providing continuous Terraform security and compliance. + +| Benchmark | Description | +|--------|---------------| +| [![Infrastructure Security](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/general)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=INFRASTRUCTURE+SECURITY) | Infrastructure Security Compliance | +| [![CIS KUBERNETES](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_kubernetes)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+KUBERNETES+V1.5) | Center for Internet Security, KUBERNETES Compliance | +| [![CIS AWS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_aws)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AWS+V1.2) | Center for Internet Security, AWS Compliance | +| [![CIS AZURE](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_azure)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AZURE+V1.1) | Center for Internet Security, AZURE Compliance | +| [![PCI-DSS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/pci)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=PCI-DSS+V3.2) | Payment Card Industry Data Security Standards Compliance | +| [![NIST-800-53](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/nist)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=NIST-800-53) | National Institute of Standards and Technology Compliance | +| [![ISO27001](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/iso)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=ISO27001) | Information Security Management System, ISO/IEC 27001 Compliance | +| [![SOC2](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/soc2)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=SOC2)| Service Organization Control 2 Compliance | +| [![CIS GCP](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_gcp)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+GCP+V1.1) | Center for Internet Security, GCP Compliance | +| [![HIPAA](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/hipaa)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=HIPAA) | Health Insurance Portability and Accountability Compliance | + + + +## Usage + + +**IMPORTANT:** We do not pin modules to versions in our examples because of the +difficulty of keeping the versions in the documentation in sync with the latest released versions. +We highly recommend that in your code you pin the version to the exact version you are +using so that your infrastructure remains stable, and update versions in a +systematic way so that they do not catch you by surprise. + +Also, because of a bug in the Terraform registry ([hashicorp/terraform#21417](https://github.com/hashicorp/terraform/issues/21417)), +the registry shows many of our inputs as required when in fact they are optional. +The table below correctly indicates which inputs are required. + + +### Defaults + +Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. +The context object is a single object that contains all the input values for `terraform-null-label`. +However, each input value can also be specified individually by name as a standard Terraform variable, +and the value of those variables, when set to something other than `null`, will override the value +in the context object. In order to allow chaining of these objects, where the context object input to one +module is transformed and passed to the next module, all the variables default to `null` or empty collections. +The actual default values used when nothing is explicitly set are describe in the documentation below. + +For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, +`terraform-null-label` will actually use the default delimiter `-` (hyphen). + +A non-obvious but intentional consequence of this design is that once a module sets a non-default value, +future modules in the chain cannot reset the value back to the original default. Insted, the new setting +becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, +so once a tag is added, it will remain in the tag set and cannot be removed, although its value can +be overwritten. + +### Simple Example + +```hcl +module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} +``` + +This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` +(you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + +Now reference the label when creating an instance: + +```hcl +resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags +} +``` + +Or define a security group: + +```hcl +resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} +``` + + +### Advanced Example + +Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + +```hcl +module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] +} + +module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] +} +``` + +
+ +### Advanced Example 2 + +Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + +```hcl +tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } +] +``` + +Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + +```hcl +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} +``` + +
+ +### Advanced Example 3 + +See [complete example](./examples/complete) for even more examples. + +This example shows how you can pass the `context` output of one label module to the next label_module, +allowing you to create one label that has the base set of values, and then creating every extra label +as a derivative of that. + +
Click to show + +```hcl +module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} +``` + +This creates label outputs like this: + +```hcl +label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" +} +label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } +} +label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } +} +label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" +} +label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" +} +label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } +} +label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" +} +label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, +] +label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" +} +label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } +} +label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } +} +label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" +} + +``` + +
+ + + + + + + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + + + + +## Share the Love + +Like this project? Please give it a ★ on [our GitHub](https://github.com/cloudposse/terraform-null-label)! (it helps us **a lot**) + +Are you using this project or any of our other projects? Consider [leaving a testimonial][testimonial]. =) + + +## Related Projects + +Check out these related projects. + +- [terraform-terraform-label](https://github.com/cloudposse/terraform-terraform-label) - Terraform Module to define a consistent naming convention by (namespace, environment, stage, name, [attributes]) + + + +## Help + +**Got a question?** We got answers. + +File a GitHub [issue](https://github.com/cloudposse/terraform-null-label/issues), send us an [email][email] or join our [Slack Community][slack]. + +[![README Commercial Support][readme_commercial_support_img]][readme_commercial_support_link] + +## DevOps Accelerator for Startups + + +We are a [**DevOps Accelerator**][commercial_support]. We'll help you build your cloud infrastructure from the ground up so you can own it. Then we'll show you how to operate it and stick around for as long as you need us. + +[![Learn More](https://img.shields.io/badge/learn%20more-success.svg?style=for-the-badge)][commercial_support] + +Work directly with our team of DevOps experts via email, slack, and video conferencing. + +We deliver 10x the value for a fraction of the cost of a full-time engineer. Our track record is not even funny. If you want things done right and you need it done FAST, then we're your best bet. + +- **Reference Architecture.** You'll get everything you need from the ground up built using 100% infrastructure as code. +- **Release Engineering.** You'll have end-to-end CI/CD with unlimited staging environments. +- **Site Reliability Engineering.** You'll have total visibility into your apps and microservices. +- **Security Baseline.** You'll have built-in governance with accountability and audit logs for all changes. +- **GitOps.** You'll be able to operate your infrastructure via Pull Requests. +- **Training.** You'll receive hands-on training so your team can operate what we build. +- **Questions.** You'll have a direct line of communication between our teams via a Shared Slack channel. +- **Troubleshooting.** You'll get help to triage when things aren't working. +- **Code Reviews.** You'll receive constructive feedback on Pull Requests. +- **Bug Fixes.** We'll rapidly work with you to fix any bugs in our projects. + +## Slack Community + +Join our [Open Source Community][slack] on Slack. It's **FREE** for everyone! Our "SweetOps" community is where you get to talk with others who share a similar vision for how to rollout and manage infrastructure. This is the best place to talk shop, ask questions, solicit feedback, and work together as a community to build totally *sweet* infrastructure. + +## Discourse Forums + +Participate in our [Discourse Forums][discourse]. Here you'll find answers to commonly asked questions. Most questions will be related to the enormous number of projects we support on our GitHub. Come here to collaborate on answers, find solutions, and get ideas about the products and services we value. It only takes a minute to get started! Just sign in with SSO using your GitHub account. + +## Newsletter + +Sign up for [our newsletter][newsletter] that covers everything on our technology radar. Receive updates on what we're up to on GitHub as well as awesome new projects we discover. + +## Office Hours + +[Join us every Wednesday via Zoom][office_hours] for our weekly "Lunch & Learn" sessions. It's **FREE** for everyone! + +[![zoom](https://img.cloudposse.com/fit-in/200x200/https://cloudposse.com/wp-content/uploads/2019/08/Powered-by-Zoom.png")][office_hours] + +## Contributing + +### Bug Reports & Feature Requests + +Please use the [issue tracker](https://github.com/cloudposse/terraform-null-label/issues) to report any bugs or file feature requests. + +### Developing + +If you are interested in being a contributor and want to get involved in developing this project or [help out](https://cpco.io/help-out) with our other projects, we would love to hear from you! Shoot us an [email][email]. + +In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. + + 1. **Fork** the repo on GitHub + 2. **Clone** the project to your own machine + 3. **Commit** changes to your own branch + 4. **Push** your work back up to your fork + 5. Submit a **Pull Request** so that we can review your changes + +**NOTE:** Be sure to merge the latest changes from "upstream" before making a pull request! + + +## Copyright + +Copyright © 2017-2021 [Cloud Posse, LLC](https://cpco.io/copyright) + + + +## License + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +See [LICENSE](LICENSE) for full details. + +```text +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +``` + + + + + + + + + +## Trademarks + +All other trademarks referenced herein are the property of their respective owners. + +## About + +This project is maintained and funded by [Cloud Posse, LLC][website]. Like it? Please let us know by [leaving a testimonial][testimonial]! + +[![Cloud Posse][logo]][website] + +We're a [DevOps Professional Services][hire] company based in Los Angeles, CA. We ❤️ [Open Source Software][we_love_open_source]. + +We offer [paid support][commercial_support] on all of our projects. + +Check out [our other projects][github], [follow us on twitter][twitter], [apply for a job][jobs], or [hire us][hire] to help with your cloud strategy and implementation. + + + +### Contributors + + +| [![Erik Osterman][osterman_avatar]][osterman_homepage]
[Erik Osterman][osterman_homepage] | [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]
[Andriy Knysh][aknysh_homepage] | [![Igor Rodionov][goruha_avatar]][goruha_homepage]
[Igor Rodionov][goruha_homepage] | [![Sergey Vasilyev][s2504s_avatar]][s2504s_homepage]
[Sergey Vasilyev][s2504s_homepage] | [![Michael Pereira][MichaelPereira_avatar]][MichaelPereira_homepage]
[Michael Pereira][MichaelPereira_homepage] | [![Jamie Nelson][Jamie-BitFlight_avatar]][Jamie-BitFlight_homepage]
[Jamie Nelson][Jamie-BitFlight_homepage] | [![Vladimir][SweetOps_avatar]][SweetOps_homepage]
[Vladimir][SweetOps_homepage] | [![Daren Desjardins][darend_avatar]][darend_homepage]
[Daren Desjardins][darend_homepage] | [![Maarten van der Hoef][maartenvanderhoef_avatar]][maartenvanderhoef_homepage]
[Maarten van der Hoef][maartenvanderhoef_homepage] | [![Adam Tibbing][tibbing_avatar]][tibbing_homepage]
[Adam Tibbing][tibbing_homepage] | +|---|---|---|---|---|---|---|---|---|---| + + + [osterman_homepage]: https://github.com/osterman + [osterman_avatar]: https://img.cloudposse.com/150x150/https://github.com/osterman.png + [aknysh_homepage]: https://github.com/aknysh + [aknysh_avatar]: https://img.cloudposse.com/150x150/https://github.com/aknysh.png + [goruha_homepage]: https://github.com/goruha + [goruha_avatar]: https://img.cloudposse.com/150x150/https://github.com/goruha.png + [s2504s_homepage]: https://github.com/s2504s + [s2504s_avatar]: https://img.cloudposse.com/150x150/https://github.com/s2504s.png + [MichaelPereira_homepage]: https://github.com/MichaelPereira + [MichaelPereira_avatar]: https://img.cloudposse.com/150x150/https://github.com/MichaelPereira.png + [Jamie-BitFlight_homepage]: https://github.com/Jamie-BitFlight + [Jamie-BitFlight_avatar]: https://img.cloudposse.com/150x150/https://github.com/Jamie-BitFlight.png + [SweetOps_homepage]: https://github.com/SweetOps + [SweetOps_avatar]: https://img.cloudposse.com/150x150/https://github.com/SweetOps.png + [darend_homepage]: https://github.com/darend + [darend_avatar]: https://img.cloudposse.com/150x150/https://github.com/darend.png + [maartenvanderhoef_homepage]: https://github.com/maartenvanderhoef + [maartenvanderhoef_avatar]: https://img.cloudposse.com/150x150/https://github.com/maartenvanderhoef.png + [tibbing_homepage]: https://github.com/tibbing + [tibbing_avatar]: https://img.cloudposse.com/150x150/https://github.com/tibbing.png + +[![README Footer][readme_footer_img]][readme_footer_link] +[![Beacon][beacon]][website] + + [logo]: https://cloudposse.com/logo-300x69.svg + [docs]: https://cpco.io/docs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=docs + [website]: https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=website + [github]: https://cpco.io/github?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=github + [jobs]: https://cpco.io/jobs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=jobs + [hire]: https://cpco.io/hire?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=hire + [slack]: https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=slack + [linkedin]: https://cpco.io/linkedin?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=linkedin + [twitter]: https://cpco.io/twitter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=twitter + [testimonial]: https://cpco.io/leave-testimonial?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=testimonial + [office_hours]: https://cloudposse.com/office-hours?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=office_hours + [newsletter]: https://cpco.io/newsletter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=newsletter + [discourse]: https://ask.sweetops.com/?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=discourse + [email]: https://cpco.io/email?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=email + [commercial_support]: https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=commercial_support + [we_love_open_source]: https://cpco.io/we-love-open-source?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=we_love_open_source + [terraform_modules]: https://cpco.io/terraform-modules?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=terraform_modules + [readme_header_img]: https://cloudposse.com/readme/header/img + [readme_header_link]: https://cloudposse.com/readme/header/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_header_link + [readme_footer_img]: https://cloudposse.com/readme/footer/img + [readme_footer_link]: https://cloudposse.com/readme/footer/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_footer_link + [readme_commercial_support_img]: https://cloudposse.com/readme/commercial-support/img + [readme_commercial_support_link]: https://cloudposse.com/readme/commercial-support/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_commercial_support_link + [share_twitter]: https://twitter.com/intent/tweet/?text=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_linkedin]: https://www.linkedin.com/shareArticle?mini=true&title=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_reddit]: https://reddit.com/submit/?url=https://github.com/cloudposse/terraform-null-label + [share_facebook]: https://facebook.com/sharer/sharer.php?u=https://github.com/cloudposse/terraform-null-label + [share_googleplus]: https://plus.google.com/share?url=https://github.com/cloudposse/terraform-null-label + [share_email]: mailto:?subject=terraform-null-label&body=https://github.com/cloudposse/terraform-null-label + [beacon]: https://ga-beacon.cloudposse.com/UA-76589703-4/cloudposse/terraform-null-label?pixel&cs=github&cm=readme&an=terraform-null-label diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/README.yaml b/.terraform/modules/datadog-integration.forwarder_rds_label/README.yaml new file mode 100755 index 0000000..42bdb84 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/README.yaml @@ -0,0 +1,618 @@ +name: terraform-null-label +tags: +- aws +- terraform +- terraform-modules +- naming-convention +- name +- namespace +- stage +categories: +- terraform-modules/supported +license: APACHE2 +github_repo: cloudposse/terraform-null-label +badges: +- name: Latest Release + image: https://img.shields.io/github/release/cloudposse/terraform-null-label.svg + url: https://github.com/cloudposse/terraform-null-label/releases/latest +- name: Slack Community + image: https://slack.cloudposse.com/badge.svg + url: https://slack.cloudposse.com +related: +- name: terraform-terraform-label + description: Terraform Module to define a consistent naming convention by (namespace, + environment, stage, name, [attributes]) + url: https://github.com/cloudposse/terraform-terraform-label +description: |- + Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + + This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. + However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). + So if you prefer the term `stage` to `environment` + you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. + - If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. + - If you want the attributes in a different order, you can specify that, too, with the `label_order` list. + - You can set a maximum length for the name, and the module will create a unique name that fits within that length. + - You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. + - The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + + It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. + For example, if you have 10 instances, there should be 10 different labels. + However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + + All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + + **NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. + With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + + - Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. + - Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. + - Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. +usage: |- + ### Defaults + + Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. + The context object is a single object that contains all the input values for `terraform-null-label`. + However, each input value can also be specified individually by name as a standard Terraform variable, + and the value of those variables, when set to something other than `null`, will override the value + in the context object. In order to allow chaining of these objects, where the context object input to one + module is transformed and passed to the next module, all the variables default to `null` or empty collections. + The actual default values used when nothing is explicitly set are describe in the documentation below. + + For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, + `terraform-null-label` will actually use the default delimiter `-` (hyphen). + + A non-obvious but intentional consequence of this design is that once a module sets a non-default value, + future modules in the chain cannot reset the value back to the original default. Insted, the new setting + becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, + so once a tag is added, it will remain in the tag set and cannot be removed, although its value can + be overwritten. + + ### Simple Example + + ```hcl + module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + ``` + + This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` + (you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + + Now reference the label when creating an instance: + + ```hcl + resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags + } + ``` + + Or define a security group: + + ```hcl + resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + } + ``` + + + ### Advanced Example + + Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + + ```hcl + module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] + } + + module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] + } + ``` + +
+ + ### Advanced Example 2 + + Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + + ```hcl + tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } + ] + ``` + + Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + + ```hcl + ################################ + # terraform-null-label example # + ################################ + module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } + } + + ####################### + # Launch template # + ####################### + resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } + } + + ###################### + # Autoscaling group # + ###################### + resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps + } + ``` + +
+ + ### Advanced Example 3 + + See [complete example](./examples/complete) for even more examples. + + This example shows how you can pass the `context` output of one label module to the next label_module, + allowing you to create one label that has the base set of values, and then creating every extra label + as a derivative of that. + +
Click to show + + ```hcl + module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } + } + + module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } + } + + module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } + } + ``` + + This creates label outputs like this: + + ```hcl + label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" + } + label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } + } + label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + } + label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" + } + label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } + } + label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" + } + label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, + ] + label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" + } + label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } + } + label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + } + label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + + ``` + +
+ +include: +- docs/targets.md +- docs/terraform.md +contributors: +- name: Erik Osterman + github: osterman +- name: Andriy Knysh + github: aknysh +- name: Igor Rodionov + github: goruha +- name: Sergey Vasilyev + github: s2504s +- name: Michael Pereira + github: MichaelPereira +- name: Jamie Nelson + github: Jamie-BitFlight +- name: Vladimir + github: SweetOps +- name: Daren Desjardins + github: darend +- name: Maarten van der Hoef + github: maartenvanderhoef +- name: Adam Tibbing + github: tibbing diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/docs/targets.md b/.terraform/modules/datadog-integration.forwarder_rds_label/docs/targets.md new file mode 100755 index 0000000..3dce8b3 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/docs/targets.md @@ -0,0 +1,12 @@ + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/docs/terraform.md b/.terraform/modules/datadog-integration.forwarder_rds_label/docs/terraform.md new file mode 100755 index 0000000..d4f48f4 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/docs/terraform.md @@ -0,0 +1,54 @@ + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars new file mode 100755 index 0000000..f7c725f --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars @@ -0,0 +1,12 @@ +namespace = "eg" +stage = "prod" +name = "app" + +tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" +} + +additional_tag_map = { + propagate_at_launch = "true" +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/autoscalinggroup/context.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/autoscalinggroup/context.tf new file mode 100755 index 0000000..b97f05f --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/autoscalinggroup/context.tf @@ -0,0 +1,216 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/autoscalinggroup/main.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/autoscalinggroup/main.tf new file mode 100755 index 0000000..f0d3aa6 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/autoscalinggroup/main.tf @@ -0,0 +1,104 @@ +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + + context = module.this.context +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template { + id = aws_launch_template.default.id + version = "$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} + +################################ +# Provider # +################################ +provider "aws" { + region = "eu-west-1" + + # Make it faster by skipping unneeded checks here + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +############################################################## +# Data sources to get VPC, subnets and security group details +############################################################## +data "aws_vpc" "default" { + default = true +} + +data "aws_subnet_ids" "all" { + vpc_id = data.aws_vpc.default.id +} + +data "aws_security_group" "default" { + vpc_id = data.aws_vpc.default.id + name = "default" +} + +data "aws_ami" "amazon_linux" { + most_recent = true + + owners = ["amazon"] + + filter { + name = "name" + + values = [ + "amzn-ami-hvm-*-x86_64-gp2", + ] + } + + filter { + name = "owner-alias" + + values = [ + "amazon", + ] + } +} + diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/autoscalinggroup/outputs.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/autoscalinggroup/outputs.tf new file mode 100755 index 0000000..f8fcce5 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/autoscalinggroup/outputs.tf @@ -0,0 +1,12 @@ +# terraform-null-label example used here: Output list of tags applied in each format +output "tags_as_list_of_maps" { + value = module.label.tags_as_list_of_maps +} + +output "tags" { + value = module.label.tags +} + +output "id" { + value = module.label.id +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/autoscalinggroup/versions.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/autoscalinggroup/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/autoscalinggroup/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/complete.auto.tfvars b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/complete.auto.tfvars new file mode 100755 index 0000000..e7bc519 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/complete.auto.tfvars @@ -0,0 +1,10 @@ +namespace = "cp" +environment = "uw2" +stage = "prd" +name = "null-label" + +delimiter = "" +id_length_limit = 6 + +label_key_case = "lower" +label_value_case = "upper" diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/context.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/context.tf new file mode 100755 index 0000000..973d4dc --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/context.tf @@ -0,0 +1,217 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label1.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label1.tf new file mode 100755 index 0000000..8da353b --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label1.tf @@ -0,0 +1,42 @@ +module "label1" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label1" { + value = { + id = module.label1.id + name = module.label1.name + namespace = module.label1.namespace + stage = module.label1.stage + attributes = module.label1.attributes + delimiter = module.label1.delimiter + } +} + +output "label1_tags" { + value = module.label1.tags +} + +output "label1_context" { + value = module.label1.context +} + +output "label1_normalized_context" { + value = module.label1.normalized_context +} + + + diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label1t1.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label1t1.tf new file mode 100755 index 0000000..2bcb362 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label1t1.tf @@ -0,0 +1,18 @@ +module "label1t1" { + source = "../../" + + id_length_limit = 28 + + context = module.label1.context +} + +output "label1t1" { + value = { + id = module.label1t1.id + id_full = module.label1t1.id_full + } +} + +output "label1t1_tags" { + value = module.label1t1.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label1t2.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label1t2.tf new file mode 100755 index 0000000..5df651e --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label1t2.tf @@ -0,0 +1,18 @@ +module "label1t2" { + source = "../../" + + id_length_limit = 29 + + context = module.label1.context +} + +output "label1t2" { + value = { + id = module.label1t2.id + id_full = module.label1t2.id_full + } +} + +output "label1t2_tags" { + value = module.label1t2.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label2.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label2.tf new file mode 100755 index 0000000..faf7450 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label2.tf @@ -0,0 +1,42 @@ +module "label2" { + source = "../../" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + regex_replace_chars = "/[^a-zA-Z0-9-+]/" + + additional_tag_map = { + propagate_at_launch = "true" + additional_tag = "yes" + } + + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +output "label2" { + value = { + id = module.label2.id + name = module.label2.name + namespace = module.label2.namespace + stage = module.label2.stage + attributes = module.label2.attributes + delimiter = module.label2.delimiter + } +} + +output "label2_tags" { + value = module.label2.tags +} + +output "label2_tags_as_list_of_maps" { + value = module.label2.tags_as_list_of_maps +} + +output "label2_context" { + value = module.label2.context +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label3c.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label3c.tf new file mode 100755 index 0000000..338a636 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label3c.tf @@ -0,0 +1,36 @@ +module "label3c" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3c" { + value = { + id = module.label3c.id + name = module.label3c.name + namespace = module.label3c.namespace + stage = module.label3c.stage + attributes = module.label3c.attributes + delimiter = module.label3c.delimiter + } +} + +output "label3c_tags" { + value = module.label3c.tags +} + +output "label3c_context" { + value = module.label3c.context +} + +output "label3c_normalized_context" { + value = module.label3c.normalized_context +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label3n.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label3n.tf new file mode 100755 index 0000000..ca51282 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label3n.tf @@ -0,0 +1,36 @@ +module "label3n" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.normalized_context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3n" { + value = { + id = module.label3n.id + name = module.label3n.name + namespace = module.label3n.namespace + stage = module.label3n.stage + attributes = module.label3n.attributes + delimiter = module.label3n.delimiter + } +} + +output "label3n_tags" { + value = module.label3n.tags +} + +output "label3n_context" { + value = module.label3n.context +} + +output "label3n_normalized_context" { + value = module.label3n.normalized_context +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label4.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label4.tf new file mode 100755 index 0000000..74e3ca1 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label4.tf @@ -0,0 +1,34 @@ +module "label4" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + name = "Example Cluster" + attributes = ["big", "fat", "honking", "cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label4" { + value = { + id = module.label4.id + name = module.label4.name + namespace = module.label4.namespace + stage = module.label4.stage + attributes = module.label4.attributes + delimiter = module.label4.delimiter + } +} + +output "label4_tags" { + value = module.label4.tags +} + +output "label4_context" { + value = module.label4.context +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label5.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label5.tf new file mode 100755 index 0000000..0f0a76e --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label5.tf @@ -0,0 +1,33 @@ +module "label5" { + source = "../../" + enabled = false + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + } +} + +output "label5" { + value = { + id = module.label5.id + name = module.label5.name + namespace = module.label5.namespace + stage = module.label5.stage + attributes = module.label5.attributes + delimiter = module.label5.delimiter + } +} + +output "label5_tags" { + value = module.label5.tags +} + +output "label5_context" { + value = module.label5.context +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label6f.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label6f.tf new file mode 100755 index 0000000..1ce1bab --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label6f.tf @@ -0,0 +1,20 @@ +module "label6f" { + source = "../../" + + delimiter = "~" + id_length_limit = 0 + + # Use values from tfvars + context = module.this.context +} + +output "label6f" { + value = { + id = module.label6f.id + id_full = module.label6f.id_full + } +} + +output "label6f_tags" { + value = module.label6f.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label6t.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label6t.tf new file mode 100755 index 0000000..b5d9bc1 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label6t.tf @@ -0,0 +1,19 @@ +module "label6t" { + source = "../../" + + # Use values from tfvars, + # specifically: complete.auto.tfvars + context = module.this.context +} + +output "label6t" { + value = { + id = module.label6t.id + id_full = module.label6t.id_full + id_length_limit = module.this.context.id_length_limit + } +} + +output "label6t_tags" { + value = module.label6t.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label7.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label7.tf new file mode 100755 index 0000000..bb365d4 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label7.tf @@ -0,0 +1,44 @@ +module "label7a" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + } +} + +module "label7" { + source = "../../" + + attributes = ["nodegroup"] + + context = module.label7a.context +} + + +output "label7" { + value = { + id = module.label7.id + name = module.label7.name + namespace = module.label7.namespace + stage = module.label7.stage + attributes = module.label7.attributes + delimiter = module.label7.delimiter + } +} + +output "label7_id" { + value = module.label7.id +} + +output "label7_attributes" { + value = module.label7.attributes +} + +output "label7_context" { + value = module.label7.context +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label8d.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label8d.tf new file mode 100755 index 0000000..4252419 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label8d.tf @@ -0,0 +1,44 @@ +module "label8d" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8d_context" { + source = "../../" + + context = module.label8d.context +} + +output "label8d_context_id" { + value = module.label8d_context.id +} + +output "label8d_context_context" { + value = module.label8d_context.context +} + +output "label8d_context_tags" { + value = module.label8d_context.tags +} + +output "label8d_id" { + value = module.label8d.id +} + +output "label8d_context" { + value = module.label8d.context +} + +output "label8d_tags" { + value = module.label8d.tags +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label8dcd.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label8dcd.tf new file mode 100755 index 0000000..ccdae21 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label8dcd.tf @@ -0,0 +1,24 @@ +module "label8dcd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "x" +} + +module "label8dcd_context" { + source = "../../" + + context = module.label8dcd.context +} + +output "label8dcd_context_id" { + value = module.label8dcd_context.id +} + +output "label8dcd_id" { + value = module.label8dcd.id +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label8dnd.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label8dnd.tf new file mode 100755 index 0000000..2edb378 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label8dnd.tf @@ -0,0 +1,24 @@ +module "label8dnd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "" +} + +module "label8dnd_context" { + source = "../../" + + context = module.label8dnd.context +} + +output "label8dnd_context_id" { + value = module.label8dnd_context.id +} + +output "label8dnd_id" { + value = module.label8dnd.id +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label8l.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label8l.tf new file mode 100755 index 0000000..7462f9e --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label8l.tf @@ -0,0 +1,46 @@ +module "label8l" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "lower" + label_value_case = "lower" + + tags = { + "kubernetes.io/cluster/" = "shared" + "upperTEST" = "testUPPER" + } +} + +module "label8l_context" { + source = "../../" + + context = module.label8l.context +} + +output "label8l_context_id" { + value = module.label8l_context.id +} + +output "label8l_context_context" { + value = module.label8l_context.context +} + +output "label8l_context_tags" { + value = module.label8l_context.tags +} + +output "label8l_id" { + value = module.label8l.id +} + +output "label8l_context" { + value = module.label8l.context +} + +output "label8l_tags" { + value = module.label8l.tags +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label8n.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label8n.tf new file mode 100755 index 0000000..fd4ad57 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label8n.tf @@ -0,0 +1,45 @@ +module "label8n" { + source = "../../" + + enabled = true + namespace = "EG" + environment = "demo" + name = "blue" + attributes = ["eks", "ClusteR"] + delimiter = "-" + label_value_case = "none" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8n_context" { + source = "../../" + + context = module.label8n.context +} + +output "label8n_context_id" { + value = module.label8n_context.id +} + +output "label8n_context_context" { + value = module.label8n_context.context +} + +output "label8n_context_tags" { + value = module.label8n_context.tags +} + +output "label8n_id" { + value = module.label8n.id +} + +output "label8n_context" { + value = module.label8n.context +} + +output "label8n_tags" { + value = module.label8n.tags +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label8t.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label8t.tf new file mode 100755 index 0000000..cb54c7a --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label8t.tf @@ -0,0 +1,45 @@ +module "label8t" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["EKS", "cluster"] + delimiter = "-" + label_key_case = "title" + label_value_case = "title" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8t_context" { + source = "../../" + + context = module.label8t.context +} + +output "label8t_context_id" { + value = module.label8t_context.id +} + +output "label8t_context_context" { + value = module.label8t_context.context +} + +output "label8t_context_tags" { + value = module.label8t_context.tags +} + +output "label8t_id" { + value = module.label8t.id +} + +output "label8t_context" { + value = module.label8t.context +} + +output "label8t_tags" { + value = module.label8t.tags +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label8u.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label8u.tf new file mode 100755 index 0000000..499535b --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/label8u.tf @@ -0,0 +1,50 @@ +module "label8u" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "upper" + label_value_case = "upper" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8u_context" { + source = "../../" + + context = module.label8u.context +} + +output "label8u_context_id" { + value = module.label8u_context.id +} + +output "label8u_context_context" { + value = module.label8u_context.context +} + +// debug +output "label8u_context_normalized_context" { + value = module.label8u_context.normalized_context +} + +output "label8u_context_tags" { + value = module.label8u_context.tags +} + +output "label8u_id" { + value = module.label8u.id +} + +output "label8u_context" { + value = module.label8u.context +} + +output "label8u_tags" { + value = module.label8u.tags +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/versions.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/examples/complete/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/exports/context.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/exports/context.tf new file mode 100755 index 0000000..81f99b4 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/exports/context.tf @@ -0,0 +1,202 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/main.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/main.tf new file mode 100755 index 0000000..0deda2b --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/main.tf @@ -0,0 +1,146 @@ +locals { + + defaults = { + label_order = ["namespace", "environment", "stage", "name", "attributes"] + regex_replace_chars = "/[^-a-zA-Z0-9]/" + delimiter = "-" + replacement = "" + id_length_limit = 0 + id_hash_length = 5 + label_key_case = "title" + label_value_case = "lower" + } + + # So far, we have decided not to allow overriding replacement or id_hash_length + replacement = local.defaults.replacement + id_hash_length = local.defaults.id_hash_length + + # The values provided by variables supersede the values inherited from the context object, + # except for tags and attributes which are merged. + input = { + # It would be nice to use coalesce here, but we cannot, because it + # is an error for all the arguments to coalesce to be empty. + enabled = var.enabled == null ? var.context.enabled : var.enabled + namespace = var.namespace == null ? var.context.namespace : var.namespace + environment = var.environment == null ? var.context.environment : var.environment + stage = var.stage == null ? var.context.stage : var.stage + name = var.name == null ? var.context.name : var.name + delimiter = var.delimiter == null ? var.context.delimiter : var.delimiter + # modules tack on attributes (passed by var) to the end of the list (passed by context) + attributes = compact(distinct(concat(coalesce(var.context.attributes, []), coalesce(var.attributes, [])))) + tags = merge(var.context.tags, var.tags) + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + label_order = var.label_order == null ? var.context.label_order : var.label_order + regex_replace_chars = var.regex_replace_chars == null ? var.context.regex_replace_chars : var.regex_replace_chars + id_length_limit = var.id_length_limit == null ? var.context.id_length_limit : var.id_length_limit + label_key_case = var.label_key_case == null ? lookup(var.context, "label_key_case", null) : var.label_key_case + label_value_case = var.label_value_case == null ? lookup(var.context, "label_value_case", null) : var.label_value_case + } + + + enabled = local.input.enabled + regex_replace_chars = coalesce(local.input.regex_replace_chars, local.defaults.regex_replace_chars) + + # string_label_names are names of inputs that are strings (not list of strings) used as labels + string_label_names = ["name", "namespace", "environment", "stage"] + normalized_labels = { for k in local.string_label_names : k => + local.input[k] == null ? "" : replace(local.input[k], local.regex_replace_chars, local.replacement) + } + normalized_attributes = compact(distinct([for v in local.input.attributes : replace(v, local.regex_replace_chars, local.replacement)])) + + formatted_labels = { for k in local.string_label_names : k => local.label_value_case == "none" ? local.normalized_labels[k] : + local.label_value_case == "title" ? title(lower(local.normalized_labels[k])) : + local.label_value_case == "upper" ? upper(local.normalized_labels[k]) : lower(local.normalized_labels[k]) + } + + attributes = compact(distinct([ + for v in local.normalized_attributes : (local.label_value_case == "none" ? v : + local.label_value_case == "title" ? title(lower(v)) : + local.label_value_case == "upper" ? upper(v) : lower(v)) + ])) + + name = local.formatted_labels["name"] + namespace = local.formatted_labels["namespace"] + environment = local.formatted_labels["environment"] + stage = local.formatted_labels["stage"] + + delimiter = local.input.delimiter == null ? local.defaults.delimiter : local.input.delimiter + label_order = local.input.label_order == null ? local.defaults.label_order : coalescelist(local.input.label_order, local.defaults.label_order) + id_length_limit = local.input.id_length_limit == null ? local.defaults.id_length_limit : local.input.id_length_limit + label_key_case = local.input.label_key_case == null ? local.defaults.label_key_case : local.input.label_key_case + label_value_case = local.input.label_value_case == null ? local.defaults.label_value_case : local.input.label_value_case + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + + tags = merge(local.generated_tags, local.input.tags) + + tags_as_list_of_maps = flatten([ + for key in keys(local.tags) : merge( + { + key = key + value = local.tags[key] + }, var.additional_tag_map) + ]) + + tags_context = { + # For AWS we need `Name` to be disambiguated since it has a special meaning + name = local.id + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = local.id_context.attributes + } + + generated_tags = { + for l in keys(local.tags_context) : + local.label_key_case == "upper" ? upper(l) : ( + local.label_key_case == "lower" ? lower(l) : title(lower(l)) + ) => local.tags_context[l] if length(local.tags_context[l]) > 0 + } + + id_context = { + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = join(local.delimiter, local.attributes) + } + + labels = [for l in local.label_order : local.id_context[l] if length(local.id_context[l]) > 0] + + id_full = join(local.delimiter, local.labels) + # Create a truncated ID if needed + delimiter_length = length(local.delimiter) + # Calculate length of normal part of ID, leaving room for delimiter and hash + id_truncated_length_limit = local.id_length_limit - (local.id_hash_length + local.delimiter_length) + # Truncate the ID and ensure a single (not double) trailing delimiter + id_truncated = local.id_truncated_length_limit <= 0 ? "" : "${trimsuffix(substr(local.id_full, 0, local.id_truncated_length_limit), local.delimiter)}${local.delimiter}" + # Support usages that disallow numeric characters. Would prefer tr 0-9 q-z but Terraform does not support it. + id_hash_plus = "${md5(local.id_full)}qrstuvwxyz" + id_hash_case = local.label_value_case == "title" ? title(local.id_hash_plus) : local.label_value_case == "upper" ? upper(local.id_hash_plus) : local.label_value_case == "lower" ? lower(local.id_hash_plus) : local.id_hash_plus + id_hash = replace(local.id_hash_case, local.regex_replace_chars, local.replacement) + # Create the short ID by adding a hash to the end of the truncated ID + id_short = substr("${local.id_truncated}${local.id_hash}", 0, local.id_length_limit) + id = local.id_length_limit != 0 && length(local.id_full) > local.id_length_limit ? local.id_short : local.id_full + + + # Context of this label to pass to other label modules + output_context = { + enabled = local.enabled + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + delimiter = local.delimiter + attributes = local.attributes + tags = local.tags + additional_tag_map = local.additional_tag_map + label_order = local.label_order + regex_replace_chars = local.regex_replace_chars + id_length_limit = local.id_length_limit + label_key_case = local.label_key_case + label_value_case = local.label_value_case + } + +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/outputs.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/outputs.tf new file mode 100755 index 0000000..87ad1be --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/outputs.tf @@ -0,0 +1,88 @@ +output "id" { + value = local.enabled ? local.id : "" + description = "Disambiguated ID restricted to `id_length_limit` characters in total" +} + +output "id_full" { + value = local.enabled ? local.id_full : "" + description = "Disambiguated ID not restricted in length" +} + +output "enabled" { + value = local.enabled + description = "True if module is enabled, false otherwise" +} + +output "namespace" { + value = local.enabled ? local.namespace : "" + description = "Normalized namespace" +} + +output "environment" { + value = local.enabled ? local.environment : "" + description = "Normalized environment" +} + +output "name" { + value = local.enabled ? local.name : "" + description = "Normalized name" +} + +output "stage" { + value = local.enabled ? local.stage : "" + description = "Normalized stage" +} + +output "delimiter" { + value = local.enabled ? local.delimiter : "" + description = "Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes`" +} + +output "attributes" { + value = local.enabled ? local.attributes : [] + description = "List of attributes" +} + +output "tags" { + value = local.enabled ? local.tags : {} + description = "Normalized Tag map" +} + +output "additional_tag_map" { + value = local.additional_tag_map + description = "The merged additional_tag_map" +} + +output "label_order" { + value = local.label_order + description = "The naming order actually used to create the ID" +} + +output "regex_replace_chars" { + value = local.regex_replace_chars + description = "The regex_replace_chars actually used to create the ID" +} + +output "id_length_limit" { + value = local.id_length_limit + description = "The id_length_limit actually used to create the ID, with `0` meaning unlimited" +} + +output "tags_as_list_of_maps" { + value = local.tags_as_list_of_maps + description = "Additional tags as a list of maps, which can be used in several AWS resources" +} + +output "normalized_context" { + value = local.output_context + description = "Normalized context of this module" +} + +output "context" { + value = local.input + description = <<-EOT + Merged but otherwise unmodified input to this module, to be used as context input to other modules. + Note: this version will have null values as defaults, not the values actually used as defaults. +EOT +} + diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/test/Makefile b/.terraform/modules/datadog-integration.forwarder_rds_label/test/Makefile new file mode 100755 index 0000000..ea15d62 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/test/Makefile @@ -0,0 +1,43 @@ +TEST_HARNESS ?= https://github.com/cloudposse/test-harness.git +TEST_HARNESS_BRANCH ?= master +TEST_HARNESS_PATH = $(realpath .test-harness) +BATS_ARGS ?= --tap +BATS_LOG ?= test.log + +# Define a macro to run the tests +define RUN_TESTS +@echo "Running tests in $(1)" +@cd $(1) && bats $(BATS_ARGS) $(addsuffix .bats,$(addprefix $(TEST_HARNESS_PATH)/test/terraform/,$(TESTS))) +endef + +default: all + +-include Makefile.* + +## Provision the test-harnesss +.test-harness: + [ -d $@ ] || git clone --depth=1 -b $(TEST_HARNESS_BRANCH) $(TEST_HARNESS) $@ + +## Initialize the tests +init: .test-harness + +## Install all dependencies (OS specific) +deps:: + @exit 0 + +## Clean up the test harness +clean: + [ "$(TEST_HARNESS_PATH)" == "/" ] || rm -rf $(TEST_HARNESS_PATH) + +## Run all tests +all: module examples/complete + +## Run basic sanity checks against the module itself +module: export TESTS ?= installed lint get-modules module-pinning get-plugins provider-pinning validate terraform-docs input-descriptions output-descriptions +module: deps + $(call RUN_TESTS, ../) + +## Run tests against example +examples/complete: export TESTS ?= installed lint get-modules get-plugins validate init plan apply +examples/complete: deps + $(call RUN_TESTS, ../$@) diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/test/Makefile.alpine b/.terraform/modules/datadog-integration.forwarder_rds_label/test/Makefile.alpine new file mode 100755 index 0000000..7925b18 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/test/Makefile.alpine @@ -0,0 +1,5 @@ +ifneq (,$(wildcard /sbin/apk)) +## Install all dependencies for alpine +deps:: init + @apk add --update terraform-docs@cloudposse json2hcl@cloudposse +endif diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/test/src/Makefile b/.terraform/modules/datadog-integration.forwarder_rds_label/test/src/Makefile new file mode 100755 index 0000000..b772822 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/test/src/Makefile @@ -0,0 +1,30 @@ +export TF_CLI_ARGS_init ?= -get-plugins=true +export TERRAFORM_VERSION ?= $(shell curl -s https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r -M '.current_version' | cut -d. -f1-2) + +.DEFAULT_GOAL : all +.PHONY: all + +## Default target +all: test + +.PHONY : init +## Initialize tests +init: + @exit 0 + +.PHONY : test +## Run tests +test: init + go mod download + go test -v -timeout 60m -run TestExamplesComplete + +## Run tests in docker container +docker/test: + docker run --name terratest --rm -it -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e GITHUB_TOKEN \ + -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" \ + -v $(CURDIR)/../../:/module/ cloudposse/test-harness:latest -C /module/test/src test + +.PHONY : clean +## Clean up files +clean: + rm -rf ../../examples/complete/*.tfstate* diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/test/src/examples_complete_test.go b/.terraform/modules/datadog-integration.forwarder_rds_label/test/src/examples_complete_test.go new file mode 100755 index 0000000..156e293 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/test/src/examples_complete_test.go @@ -0,0 +1,293 @@ +package test + +import ( + "fmt" + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" + "github.com/qdm12/reprint" + "github.com/stretchr/testify/assert" +) + +type NLContext struct { + AdditionalTagMap map[string]string `json:"additional_tag_map"` + Attributes []string `json:"attributes"` + Delimiter interface{} `json:"delimiter"` + Enabled bool `json:"enabled"` + Environment interface{} `json:"environment"` + LabelOrder []string `json:"label_order"` + Name interface{} `json:"name"` + Namespace interface{} `json:"namespace"` + RegexReplaceChars interface{} `json:"regex_replace_chars"` + Stage interface{} `json:"stage"` + Tags map[string]string `json:"tags"` +} + +// Test the Terraform module in examples/complete using Terratest. +func TestExamplesComplete(t *testing.T) { + t.Parallel() + + terraformOptions := &terraform.Options{ + // The path to where our Terraform code is located + TerraformDir: "../../examples/complete", + Upgrade: true, + } + + // At the end of the test, run `terraform destroy` to clean up any resources that were created + defer terraform.Destroy(t, terraformOptions) + + // This will run `terraform init` and `terraform apply` and fail the test if there are any errors + terraform.InitAndApply(t, terraformOptions) + + expectedLabel1Context := NLContext{ + Enabled: true, + Namespace: "CloudPosse", + Environment: "UAT", + Stage: "build", + Name: "Winston Churchroom", + Attributes: []string{"fire", "water", "earth", "air"}, + Delimiter: "-", + LabelOrder: []string{"name", "environment", "stage", "attributes"}, + Tags: map[string]string{ + "City": "Dublin", + "Environment": "Private", + }, + AdditionalTagMap: map[string]string{}, + } + + var expectedLabel1NormalizedContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel1NormalizedContext) + expectedLabel1NormalizedContext.Namespace = "cloudposse" + expectedLabel1NormalizedContext.Environment = "uat" + expectedLabel1NormalizedContext.Name = "winstonchurchroom" + expectedLabel1NormalizedContext.RegexReplaceChars = "/[^-a-zA-Z0-9]/" + expectedLabel1NormalizedContext.Tags = map[string]string{ + "City": "Dublin", + "Environment": "Private", + "Namespace": "cloudposse", + "Stage": "build", + "Name": "winstonchurchroom-uat-build-fire-water-earth-air", + "Attributes": "fire-water-earth-air", + } + + var label1NormalizedContext, label1Context NLContext + // Run `terraform output` to get the value of an output variable + label1 := terraform.OutputMap(t, terraformOptions, "label1") + label1Tags := terraform.OutputMap(t, terraformOptions, "label1_tags") + terraform.OutputStruct(t, terraformOptions, "label1_normalized_context", &label1NormalizedContext) + terraform.OutputStruct(t, terraformOptions, "label1_context", &label1Context) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1["id"]) + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1Tags["Name"]) + assert.Equal(t, "Dublin", label1Tags["City"]) + assert.Equal(t, "Private", label1Tags["Environment"]) + assert.Equal(t, expectedLabel1NormalizedContext, label1NormalizedContext) + assert.Equal(t, expectedLabel1Context, label1Context) + + label1t1 := terraform.OutputMap(t, terraformOptions, "label1t1") + label1t1Tags := terraform.OutputMap(t, terraformOptions, "label1t1_tags") + assert.Equal(t, "winstonchurchroom-uat-6a0b34", label1t1["id"], + "Extra hash character should be added when trailing delimiter is removed") + assert.Equal(t, label1["id"], label1t1["id_full"], "id_full should not be truncated") + assert.Equal(t, label1t1["id"], label1t1Tags["Name"], "Name tag should match ID") + + label1t2 := terraform.OutputMap(t, terraformOptions, "label1t2") + label1t2Tags := terraform.OutputMap(t, terraformOptions, "label1t2_tags") + assert.Equal(t, "winstonchurchroom-uat-b-6a0b3", label1t2["id"]) + assert.Equal(t, label1t2["id"], label1t2Tags["Name"], "Name tag should match ID") + + // Run `terraform output` to get the value of an output variable + label2 := terraform.OutputMap(t, terraformOptions, "label2") + label2Tags := terraform.OutputMap(t, terraformOptions, "label2_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2["id"]) + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2Tags["Name"]) + assert.Equal(t, "London", label2Tags["City"]) + assert.Equal(t, "Public", label2Tags["Environment"]) + + var expectedLabel3cContext, label3cContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel3cContext) + expectedLabel3cContext.Name = "Starfish" + expectedLabel3cContext.Stage = "release" + expectedLabel3cContext.Delimiter = "." + expectedLabel3cContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3cContext.Tags["Eat"] = "Carrot" + expectedLabel3cContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3c := terraform.OutputMap(t, terraformOptions, "label3c") + label3cTags := terraform.OutputMap(t, terraformOptions, "label3c_tags") + terraform.OutputStruct(t, terraformOptions, "label3c_context", &label3cContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3c["id"]) + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3cTags["Name"]) + assert.Equal(t, expectedLabel3cContext, label3cContext) + + var expectedLabel3nContext, label3nContext NLContext + _ = reprint.FromTo(&expectedLabel1NormalizedContext, &expectedLabel3nContext) + expectedLabel3nContext.Name = "Starfish" + expectedLabel3nContext.Stage = "release" + expectedLabel3nContext.Delimiter = "." + expectedLabel3nContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3nContext.Tags["Eat"] = "Carrot" + expectedLabel3nContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3n := terraform.OutputMap(t, terraformOptions, "label3n") + label3nTags := terraform.OutputMap(t, terraformOptions, "label3n_tags") + terraform.OutputStruct(t, terraformOptions, "label3n_context", &label3nContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3n["id"]) + assert.Equal(t, label1Tags["Name"], label3nTags["Name"], + "Tag from label1 normalized context should overwrite label3n generated tag") + assert.Equal(t, expectedLabel3nContext, label3nContext) + + // Run `terraform output` to get the value of an output variable + label4 := terraform.OutputMap(t, terraformOptions, "label4") + label4Tags := terraform.OutputMap(t, terraformOptions, "label4_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4["id"]) + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4Tags["Name"]) + + // Run `terraform output` to get the value of an output variable + label5 := terraform.OutputMap(t, terraformOptions, "label5") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "", label5["id"]) + + label6f := terraform.OutputMap(t, terraformOptions, "label6f") + label6fTags := terraform.OutputMap(t, terraformOptions, "label6f_tags") + // Test of setting var.label_key_case = "lower", var.label_value_case = "upper" + assert.Equal(t, "CP~UW2~PRD~NULL-LABEL", label6f["id_full"]) + assert.Equal(t, label6f["id_full"], label6f["id"], "id should not be truncated") + assert.Equal(t, label6f["id"], label6fTags["name"], "Name tag should match ID") + + label6t := terraform.OutputMap(t, terraformOptions, "label6t") + label6tTags := terraform.OutputMap(t, terraformOptions, "label6t_tags") + assert.Equal(t, "CPUW2PRDNULL-LABEL", label6t["id_full"]) + assert.NotEqual(t, label6t["id_full"], label6t["id"], "id should be truncated") + assert.Equal(t, label6t["id"], label6tTags["name"], "Name tag should match ID") + assert.Equal(t, label6t["id_length_limit"], fmt.Sprintf("%d", len(label6t["id"])), + "Truncated ID length should equal length limit") + + label7 := terraform.OutputMap(t, terraformOptions, "label7") + assert.Equal(t, "eg-demo-blue-cluster-nodegroup", label7["id"], "var.attributes should be appended after context.attributes") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter=""` returns expected value of id, context id + label8dndID := terraform.Output(t, terraformOptions, "label8dnd_id") + label8dndContextID := terraform.Output(t, terraformOptions, "label8dnd_context_id") + assert.Equal(t, "egdemobluecluster", label8dndID) + assert.Equal(t, label8dndID, label8dndContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter="x"` returns expected value of id, context id + label8dcdID := terraform.Output(t, terraformOptions, "label8dcd_id") + label8dcdContextID := terraform.Output(t, terraformOptions, "label8dcd_context_id") + assert.Equal(t, "egxdemoxbluexcluster", label8dcdID) + assert.Equal(t, label8dcdID, label8dcdContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=lower` returns expected values of id, tags, context tags + label8dExpectedTags := map[string]string{ + "Attributes": "cluster", + "Environment": "demo", + "Name": "eg-demo-blue-cluster", + "Namespace": "eg", + "kubernetes.io/cluster/": "shared", + } + + label8dID := terraform.Output(t, terraformOptions, "label8d_id") + label8dContextID := terraform.Output(t, terraformOptions, "label8d_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8dID) + assert.Equal(t, label8dID, label8dContextID, "ID and context ID should be equal") + + label8dTags := terraform.OutputMap(t, terraformOptions, "label8d_tags") + label8dContextTags := terraform.OutputMap(t, terraformOptions, "label8d_context_tags") + + assert.Exactly(t, label8dExpectedTags, label8dTags, "generated tags are different from expected") + assert.Exactly(t, label8dTags, label8dContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=lower` and `label_value_case=lower` returns expected values of id, tags, context tags + label8lExpectedTags := map[string]string{ + "attributes": "cluster", + "environment": "demo", + "name": "eg-demo-blue-cluster", + "namespace": "eg", + "kubernetes.io/cluster/": "shared", + "upperTEST": "testUPPER", + } + + label8lID := terraform.Output(t, terraformOptions, "label8l_id") + label8lContextID := terraform.Output(t, terraformOptions, "label8l_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8lID) + assert.Equal(t, label8lID, label8lContextID, "ID and context ID should be equal") + + label8lTags := terraform.OutputMap(t, terraformOptions, "label8l_tags") + label8lContextTags := terraform.OutputMap(t, terraformOptions, "label8l_context_tags") + + assert.Exactly(t, label8lExpectedTags, label8lTags, "generated tags are different from expected") + assert.Exactly(t, label8lTags, label8lContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=title` returns expected values of id, tags, context tags + label8tExpectedTags := map[string]string{ + "Attributes": "Eks-Cluster", + "Environment": "Demo", + "Name": "Eg-Demo-Blue-Eks-Cluster", + "Namespace": "Eg", + "kubernetes.io/cluster/": "shared", + } + + label8tID := terraform.Output(t, terraformOptions, "label8t_id") + label8tContextID := terraform.Output(t, terraformOptions, "label8t_context_id") + assert.Equal(t, "Eg-Demo-Blue-Eks-Cluster", label8tID) + assert.Equal(t, label8tID, label8tContextID, "ID and context ID should be equal") + + label8tTags := terraform.OutputMap(t, terraformOptions, "label8t_tags") + label8tContextTags := terraform.OutputMap(t, terraformOptions, "label8t_context_tags") + + assert.Exactly(t, label8tExpectedTags, label8tTags, "generated tags are different from expected") + assert.Exactly(t, label8tTags, label8tContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=upper` and `label_value_case=upper` returns expected values of id, tags, context tags + label8uExpectedTags := map[string]string{ + "ATTRIBUTES": "CLUSTER", + "ENVIRONMENT": "DEMO", + "NAME": "EG-DEMO-BLUE-CLUSTER", + "NAMESPACE": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8uID := terraform.Output(t, terraformOptions, "label8u_id") + label8uContextID := terraform.Output(t, terraformOptions, "label8u_context_id") + assert.Equal(t, "EG-DEMO-BLUE-CLUSTER", label8uID) + assert.Equal(t, label8uID, label8uContextID, "ID and context ID should be equal") + + label8uTags := terraform.OutputMap(t, terraformOptions, "label8u_tags") + label8uContextTags := terraform.OutputMap(t, terraformOptions, "label8u_context_tags") + + assert.Exactly(t, label8uExpectedTags, label8uTags, "generated tags are different from expected") + assert.Exactly(t, label8uTags, label8uContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=none` returns expected values of id, tags, context tags + label8nExpectedTags := map[string]string{ + "Attributes": "eks-ClusteR", + "Environment": "demo", + "Name": "EG-demo-blue-eks-ClusteR", + "Namespace": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8nID := terraform.Output(t, terraformOptions, "label8n_id") + label8nContextID := terraform.Output(t, terraformOptions, "label8n_context_id") + assert.Equal(t, "EG-demo-blue-eks-ClusteR", label8nID) + assert.Equal(t, label8nID, label8nContextID, "ID and context ID should be equal") + + label8nTags := terraform.OutputMap(t, terraformOptions, "label8n_tags") + label8nContextTags := terraform.OutputMap(t, terraformOptions, "label8n_context_tags") + + assert.Exactly(t, label8nExpectedTags, label8nTags, "generated tags are different from expected") + assert.Exactly(t, label8nTags, label8nContextTags, "tags and context tags should be equal") +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/test/src/go.mod b/.terraform/modules/datadog-integration.forwarder_rds_label/test/src/go.mod new file mode 100755 index 0000000..d866541 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/test/src/go.mod @@ -0,0 +1,9 @@ +module github.com/cloudposse/terraform-null-label + +go 1.14 + +require ( + github.com/gruntwork-io/terratest v0.31.1 + github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 + github.com/stretchr/testify v1.6.1 +) diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/test/src/go.sum b/.terraform/modules/datadog-integration.forwarder_rds_label/test/src/go.sum new file mode 100755 index 0000000..b8d46b1 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/test/src/go.sum @@ -0,0 +1,595 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= +github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.5/go.mod h1:foo3aIXRQ90zFve3r0QiDsrjGDUwWhKl0ZOQy1CT14k= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= +github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200109221225-a4f60165b7a3/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= +github.com/gruntwork-io/terratest v0.31.1 h1:MPGe/5pGgJAIZ/hb+0LM1KyJKSi/QyxSkHoP9/CBhJg= +github.com/gruntwork-io/terratest v0.31.1/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= +github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4= +github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= +github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= +k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= +k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= +k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= +k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= +k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= +k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= +k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= +modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/variables.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/variables.tf new file mode 100755 index 0000000..40fb268 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/variables.tf @@ -0,0 +1,157 @@ +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} diff --git a/.terraform/modules/datadog-integration.forwarder_rds_label/versions.tf b/.terraform/modules/datadog-integration.forwarder_rds_label/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog-integration.forwarder_rds_label/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog-integration.lambda_label/LICENSE b/.terraform/modules/datadog-integration.lambda_label/LICENSE new file mode 100755 index 0000000..c844c70 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017-2020 Cloud Posse, LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/.terraform/modules/datadog-integration.lambda_label/Makefile b/.terraform/modules/datadog-integration.lambda_label/Makefile new file mode 100755 index 0000000..97d8087 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/Makefile @@ -0,0 +1,10 @@ +SHELL := /bin/bash + +# List of targets the `readme` target should call before generating the readme +export README_DEPS ?= docs/targets.md docs/terraform.md + +-include $(shell curl -sSL -o .build-harness "https://git.io/build-harness"; echo .build-harness) + +## Lint terraform code +lint: + $(SELF) terraform/install terraform/get-modules terraform/get-plugins terraform/lint terraform/validate diff --git a/.terraform/modules/datadog-integration.lambda_label/README.md b/.terraform/modules/datadog-integration.lambda_label/README.md new file mode 100755 index 0000000..32950e4 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/README.md @@ -0,0 +1,938 @@ + +# terraform-null-label [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-null-label.svg)](https://github.com/cloudposse/terraform-null-label/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) + + +[![README Header][readme_header_img]][readme_header_link] + +[![Cloud Posse][logo]](https://cpco.io/homepage) + + + +Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + +This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. +However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). +So if you prefer the term `stage` to `environment` +you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. +- If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. +- If you want the attributes in a different order, you can specify that, too, with the `label_order` list. +- You can set a maximum length for the name, and the module will create a unique name that fits within that length. +- You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. +- The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + +It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. +For example, if you have 10 instances, there should be 10 different labels. +However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + +All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + +**NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. +With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + +- Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. +- Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. +- Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. + + +--- + +This project is part of our comprehensive ["SweetOps"](https://cpco.io/sweetops) approach towards DevOps. +[][share_email] +[][share_googleplus] +[][share_facebook] +[][share_reddit] +[][share_linkedin] +[][share_twitter] + + +[![Terraform Open Source Modules](https://docs.cloudposse.com/images/terraform-open-source-modules.svg)][terraform_modules] + + + +It's 100% Open Source and licensed under the [APACHE2](LICENSE). + + + + + + + +We literally have [*hundreds of terraform modules*][terraform_modules] that are Open Source and well-maintained. Check them out! + + + + + + + +## Security & Compliance [](https://bridgecrew.io/) + +Security scanning is graciously provided by Bridgecrew. Bridgecrew is the leading fully hosted, cloud-native solution providing continuous Terraform security and compliance. + +| Benchmark | Description | +|--------|---------------| +| [![Infrastructure Security](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/general)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=INFRASTRUCTURE+SECURITY) | Infrastructure Security Compliance | +| [![CIS KUBERNETES](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_kubernetes)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+KUBERNETES+V1.5) | Center for Internet Security, KUBERNETES Compliance | +| [![CIS AWS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_aws)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AWS+V1.2) | Center for Internet Security, AWS Compliance | +| [![CIS AZURE](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_azure)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AZURE+V1.1) | Center for Internet Security, AZURE Compliance | +| [![PCI-DSS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/pci)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=PCI-DSS+V3.2) | Payment Card Industry Data Security Standards Compliance | +| [![NIST-800-53](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/nist)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=NIST-800-53) | National Institute of Standards and Technology Compliance | +| [![ISO27001](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/iso)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=ISO27001) | Information Security Management System, ISO/IEC 27001 Compliance | +| [![SOC2](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/soc2)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=SOC2)| Service Organization Control 2 Compliance | +| [![CIS GCP](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_gcp)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+GCP+V1.1) | Center for Internet Security, GCP Compliance | +| [![HIPAA](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/hipaa)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=HIPAA) | Health Insurance Portability and Accountability Compliance | + + + +## Usage + + +**IMPORTANT:** We do not pin modules to versions in our examples because of the +difficulty of keeping the versions in the documentation in sync with the latest released versions. +We highly recommend that in your code you pin the version to the exact version you are +using so that your infrastructure remains stable, and update versions in a +systematic way so that they do not catch you by surprise. + +Also, because of a bug in the Terraform registry ([hashicorp/terraform#21417](https://github.com/hashicorp/terraform/issues/21417)), +the registry shows many of our inputs as required when in fact they are optional. +The table below correctly indicates which inputs are required. + + +### Defaults + +Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. +The context object is a single object that contains all the input values for `terraform-null-label`. +However, each input value can also be specified individually by name as a standard Terraform variable, +and the value of those variables, when set to something other than `null`, will override the value +in the context object. In order to allow chaining of these objects, where the context object input to one +module is transformed and passed to the next module, all the variables default to `null` or empty collections. +The actual default values used when nothing is explicitly set are describe in the documentation below. + +For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, +`terraform-null-label` will actually use the default delimiter `-` (hyphen). + +A non-obvious but intentional consequence of this design is that once a module sets a non-default value, +future modules in the chain cannot reset the value back to the original default. Insted, the new setting +becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, +so once a tag is added, it will remain in the tag set and cannot be removed, although its value can +be overwritten. + +### Simple Example + +```hcl +module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} +``` + +This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` +(you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + +Now reference the label when creating an instance: + +```hcl +resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags +} +``` + +Or define a security group: + +```hcl +resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} +``` + + +### Advanced Example + +Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + +```hcl +module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] +} + +module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] +} +``` + +
+ +### Advanced Example 2 + +Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + +```hcl +tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } +] +``` + +Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + +```hcl +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} +``` + +
+ +### Advanced Example 3 + +See [complete example](./examples/complete) for even more examples. + +This example shows how you can pass the `context` output of one label module to the next label_module, +allowing you to create one label that has the base set of values, and then creating every extra label +as a derivative of that. + +
Click to show + +```hcl +module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} +``` + +This creates label outputs like this: + +```hcl +label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" +} +label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } +} +label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } +} +label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" +} +label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" +} +label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } +} +label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" +} +label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, +] +label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" +} +label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } +} +label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } +} +label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" +} + +``` + +
+ + + + + + + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + + + + +## Share the Love + +Like this project? Please give it a ★ on [our GitHub](https://github.com/cloudposse/terraform-null-label)! (it helps us **a lot**) + +Are you using this project or any of our other projects? Consider [leaving a testimonial][testimonial]. =) + + +## Related Projects + +Check out these related projects. + +- [terraform-terraform-label](https://github.com/cloudposse/terraform-terraform-label) - Terraform Module to define a consistent naming convention by (namespace, environment, stage, name, [attributes]) + + + +## Help + +**Got a question?** We got answers. + +File a GitHub [issue](https://github.com/cloudposse/terraform-null-label/issues), send us an [email][email] or join our [Slack Community][slack]. + +[![README Commercial Support][readme_commercial_support_img]][readme_commercial_support_link] + +## DevOps Accelerator for Startups + + +We are a [**DevOps Accelerator**][commercial_support]. We'll help you build your cloud infrastructure from the ground up so you can own it. Then we'll show you how to operate it and stick around for as long as you need us. + +[![Learn More](https://img.shields.io/badge/learn%20more-success.svg?style=for-the-badge)][commercial_support] + +Work directly with our team of DevOps experts via email, slack, and video conferencing. + +We deliver 10x the value for a fraction of the cost of a full-time engineer. Our track record is not even funny. If you want things done right and you need it done FAST, then we're your best bet. + +- **Reference Architecture.** You'll get everything you need from the ground up built using 100% infrastructure as code. +- **Release Engineering.** You'll have end-to-end CI/CD with unlimited staging environments. +- **Site Reliability Engineering.** You'll have total visibility into your apps and microservices. +- **Security Baseline.** You'll have built-in governance with accountability and audit logs for all changes. +- **GitOps.** You'll be able to operate your infrastructure via Pull Requests. +- **Training.** You'll receive hands-on training so your team can operate what we build. +- **Questions.** You'll have a direct line of communication between our teams via a Shared Slack channel. +- **Troubleshooting.** You'll get help to triage when things aren't working. +- **Code Reviews.** You'll receive constructive feedback on Pull Requests. +- **Bug Fixes.** We'll rapidly work with you to fix any bugs in our projects. + +## Slack Community + +Join our [Open Source Community][slack] on Slack. It's **FREE** for everyone! Our "SweetOps" community is where you get to talk with others who share a similar vision for how to rollout and manage infrastructure. This is the best place to talk shop, ask questions, solicit feedback, and work together as a community to build totally *sweet* infrastructure. + +## Discourse Forums + +Participate in our [Discourse Forums][discourse]. Here you'll find answers to commonly asked questions. Most questions will be related to the enormous number of projects we support on our GitHub. Come here to collaborate on answers, find solutions, and get ideas about the products and services we value. It only takes a minute to get started! Just sign in with SSO using your GitHub account. + +## Newsletter + +Sign up for [our newsletter][newsletter] that covers everything on our technology radar. Receive updates on what we're up to on GitHub as well as awesome new projects we discover. + +## Office Hours + +[Join us every Wednesday via Zoom][office_hours] for our weekly "Lunch & Learn" sessions. It's **FREE** for everyone! + +[![zoom](https://img.cloudposse.com/fit-in/200x200/https://cloudposse.com/wp-content/uploads/2019/08/Powered-by-Zoom.png")][office_hours] + +## Contributing + +### Bug Reports & Feature Requests + +Please use the [issue tracker](https://github.com/cloudposse/terraform-null-label/issues) to report any bugs or file feature requests. + +### Developing + +If you are interested in being a contributor and want to get involved in developing this project or [help out](https://cpco.io/help-out) with our other projects, we would love to hear from you! Shoot us an [email][email]. + +In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. + + 1. **Fork** the repo on GitHub + 2. **Clone** the project to your own machine + 3. **Commit** changes to your own branch + 4. **Push** your work back up to your fork + 5. Submit a **Pull Request** so that we can review your changes + +**NOTE:** Be sure to merge the latest changes from "upstream" before making a pull request! + + +## Copyright + +Copyright © 2017-2021 [Cloud Posse, LLC](https://cpco.io/copyright) + + + +## License + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +See [LICENSE](LICENSE) for full details. + +```text +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +``` + + + + + + + + + +## Trademarks + +All other trademarks referenced herein are the property of their respective owners. + +## About + +This project is maintained and funded by [Cloud Posse, LLC][website]. Like it? Please let us know by [leaving a testimonial][testimonial]! + +[![Cloud Posse][logo]][website] + +We're a [DevOps Professional Services][hire] company based in Los Angeles, CA. We ❤️ [Open Source Software][we_love_open_source]. + +We offer [paid support][commercial_support] on all of our projects. + +Check out [our other projects][github], [follow us on twitter][twitter], [apply for a job][jobs], or [hire us][hire] to help with your cloud strategy and implementation. + + + +### Contributors + + +| [![Erik Osterman][osterman_avatar]][osterman_homepage]
[Erik Osterman][osterman_homepage] | [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]
[Andriy Knysh][aknysh_homepage] | [![Igor Rodionov][goruha_avatar]][goruha_homepage]
[Igor Rodionov][goruha_homepage] | [![Sergey Vasilyev][s2504s_avatar]][s2504s_homepage]
[Sergey Vasilyev][s2504s_homepage] | [![Michael Pereira][MichaelPereira_avatar]][MichaelPereira_homepage]
[Michael Pereira][MichaelPereira_homepage] | [![Jamie Nelson][Jamie-BitFlight_avatar]][Jamie-BitFlight_homepage]
[Jamie Nelson][Jamie-BitFlight_homepage] | [![Vladimir][SweetOps_avatar]][SweetOps_homepage]
[Vladimir][SweetOps_homepage] | [![Daren Desjardins][darend_avatar]][darend_homepage]
[Daren Desjardins][darend_homepage] | [![Maarten van der Hoef][maartenvanderhoef_avatar]][maartenvanderhoef_homepage]
[Maarten van der Hoef][maartenvanderhoef_homepage] | [![Adam Tibbing][tibbing_avatar]][tibbing_homepage]
[Adam Tibbing][tibbing_homepage] | +|---|---|---|---|---|---|---|---|---|---| + + + [osterman_homepage]: https://github.com/osterman + [osterman_avatar]: https://img.cloudposse.com/150x150/https://github.com/osterman.png + [aknysh_homepage]: https://github.com/aknysh + [aknysh_avatar]: https://img.cloudposse.com/150x150/https://github.com/aknysh.png + [goruha_homepage]: https://github.com/goruha + [goruha_avatar]: https://img.cloudposse.com/150x150/https://github.com/goruha.png + [s2504s_homepage]: https://github.com/s2504s + [s2504s_avatar]: https://img.cloudposse.com/150x150/https://github.com/s2504s.png + [MichaelPereira_homepage]: https://github.com/MichaelPereira + [MichaelPereira_avatar]: https://img.cloudposse.com/150x150/https://github.com/MichaelPereira.png + [Jamie-BitFlight_homepage]: https://github.com/Jamie-BitFlight + [Jamie-BitFlight_avatar]: https://img.cloudposse.com/150x150/https://github.com/Jamie-BitFlight.png + [SweetOps_homepage]: https://github.com/SweetOps + [SweetOps_avatar]: https://img.cloudposse.com/150x150/https://github.com/SweetOps.png + [darend_homepage]: https://github.com/darend + [darend_avatar]: https://img.cloudposse.com/150x150/https://github.com/darend.png + [maartenvanderhoef_homepage]: https://github.com/maartenvanderhoef + [maartenvanderhoef_avatar]: https://img.cloudposse.com/150x150/https://github.com/maartenvanderhoef.png + [tibbing_homepage]: https://github.com/tibbing + [tibbing_avatar]: https://img.cloudposse.com/150x150/https://github.com/tibbing.png + +[![README Footer][readme_footer_img]][readme_footer_link] +[![Beacon][beacon]][website] + + [logo]: https://cloudposse.com/logo-300x69.svg + [docs]: https://cpco.io/docs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=docs + [website]: https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=website + [github]: https://cpco.io/github?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=github + [jobs]: https://cpco.io/jobs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=jobs + [hire]: https://cpco.io/hire?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=hire + [slack]: https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=slack + [linkedin]: https://cpco.io/linkedin?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=linkedin + [twitter]: https://cpco.io/twitter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=twitter + [testimonial]: https://cpco.io/leave-testimonial?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=testimonial + [office_hours]: https://cloudposse.com/office-hours?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=office_hours + [newsletter]: https://cpco.io/newsletter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=newsletter + [discourse]: https://ask.sweetops.com/?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=discourse + [email]: https://cpco.io/email?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=email + [commercial_support]: https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=commercial_support + [we_love_open_source]: https://cpco.io/we-love-open-source?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=we_love_open_source + [terraform_modules]: https://cpco.io/terraform-modules?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=terraform_modules + [readme_header_img]: https://cloudposse.com/readme/header/img + [readme_header_link]: https://cloudposse.com/readme/header/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_header_link + [readme_footer_img]: https://cloudposse.com/readme/footer/img + [readme_footer_link]: https://cloudposse.com/readme/footer/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_footer_link + [readme_commercial_support_img]: https://cloudposse.com/readme/commercial-support/img + [readme_commercial_support_link]: https://cloudposse.com/readme/commercial-support/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_commercial_support_link + [share_twitter]: https://twitter.com/intent/tweet/?text=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_linkedin]: https://www.linkedin.com/shareArticle?mini=true&title=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_reddit]: https://reddit.com/submit/?url=https://github.com/cloudposse/terraform-null-label + [share_facebook]: https://facebook.com/sharer/sharer.php?u=https://github.com/cloudposse/terraform-null-label + [share_googleplus]: https://plus.google.com/share?url=https://github.com/cloudposse/terraform-null-label + [share_email]: mailto:?subject=terraform-null-label&body=https://github.com/cloudposse/terraform-null-label + [beacon]: https://ga-beacon.cloudposse.com/UA-76589703-4/cloudposse/terraform-null-label?pixel&cs=github&cm=readme&an=terraform-null-label diff --git a/.terraform/modules/datadog-integration.lambda_label/README.yaml b/.terraform/modules/datadog-integration.lambda_label/README.yaml new file mode 100755 index 0000000..42bdb84 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/README.yaml @@ -0,0 +1,618 @@ +name: terraform-null-label +tags: +- aws +- terraform +- terraform-modules +- naming-convention +- name +- namespace +- stage +categories: +- terraform-modules/supported +license: APACHE2 +github_repo: cloudposse/terraform-null-label +badges: +- name: Latest Release + image: https://img.shields.io/github/release/cloudposse/terraform-null-label.svg + url: https://github.com/cloudposse/terraform-null-label/releases/latest +- name: Slack Community + image: https://slack.cloudposse.com/badge.svg + url: https://slack.cloudposse.com +related: +- name: terraform-terraform-label + description: Terraform Module to define a consistent naming convention by (namespace, + environment, stage, name, [attributes]) + url: https://github.com/cloudposse/terraform-terraform-label +description: |- + Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + + This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. + However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). + So if you prefer the term `stage` to `environment` + you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. + - If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. + - If you want the attributes in a different order, you can specify that, too, with the `label_order` list. + - You can set a maximum length for the name, and the module will create a unique name that fits within that length. + - You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. + - The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + + It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. + For example, if you have 10 instances, there should be 10 different labels. + However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + + All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + + **NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. + With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + + - Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. + - Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. + - Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. +usage: |- + ### Defaults + + Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. + The context object is a single object that contains all the input values for `terraform-null-label`. + However, each input value can also be specified individually by name as a standard Terraform variable, + and the value of those variables, when set to something other than `null`, will override the value + in the context object. In order to allow chaining of these objects, where the context object input to one + module is transformed and passed to the next module, all the variables default to `null` or empty collections. + The actual default values used when nothing is explicitly set are describe in the documentation below. + + For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, + `terraform-null-label` will actually use the default delimiter `-` (hyphen). + + A non-obvious but intentional consequence of this design is that once a module sets a non-default value, + future modules in the chain cannot reset the value back to the original default. Insted, the new setting + becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, + so once a tag is added, it will remain in the tag set and cannot be removed, although its value can + be overwritten. + + ### Simple Example + + ```hcl + module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + ``` + + This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` + (you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + + Now reference the label when creating an instance: + + ```hcl + resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags + } + ``` + + Or define a security group: + + ```hcl + resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + } + ``` + + + ### Advanced Example + + Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + + ```hcl + module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] + } + + module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] + } + ``` + +
+ + ### Advanced Example 2 + + Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + + ```hcl + tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } + ] + ``` + + Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + + ```hcl + ################################ + # terraform-null-label example # + ################################ + module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } + } + + ####################### + # Launch template # + ####################### + resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } + } + + ###################### + # Autoscaling group # + ###################### + resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps + } + ``` + +
+ + ### Advanced Example 3 + + See [complete example](./examples/complete) for even more examples. + + This example shows how you can pass the `context` output of one label module to the next label_module, + allowing you to create one label that has the base set of values, and then creating every extra label + as a derivative of that. + +
Click to show + + ```hcl + module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } + } + + module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } + } + + module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } + } + ``` + + This creates label outputs like this: + + ```hcl + label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" + } + label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } + } + label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + } + label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" + } + label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } + } + label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" + } + label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, + ] + label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" + } + label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } + } + label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + } + label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + + ``` + +
+ +include: +- docs/targets.md +- docs/terraform.md +contributors: +- name: Erik Osterman + github: osterman +- name: Andriy Knysh + github: aknysh +- name: Igor Rodionov + github: goruha +- name: Sergey Vasilyev + github: s2504s +- name: Michael Pereira + github: MichaelPereira +- name: Jamie Nelson + github: Jamie-BitFlight +- name: Vladimir + github: SweetOps +- name: Daren Desjardins + github: darend +- name: Maarten van der Hoef + github: maartenvanderhoef +- name: Adam Tibbing + github: tibbing diff --git a/.terraform/modules/datadog-integration.lambda_label/docs/targets.md b/.terraform/modules/datadog-integration.lambda_label/docs/targets.md new file mode 100755 index 0000000..3dce8b3 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/docs/targets.md @@ -0,0 +1,12 @@ + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + diff --git a/.terraform/modules/datadog-integration.lambda_label/docs/terraform.md b/.terraform/modules/datadog-integration.lambda_label/docs/terraform.md new file mode 100755 index 0000000..d4f48f4 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/docs/terraform.md @@ -0,0 +1,54 @@ + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars b/.terraform/modules/datadog-integration.lambda_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars new file mode 100755 index 0000000..f7c725f --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars @@ -0,0 +1,12 @@ +namespace = "eg" +stage = "prod" +name = "app" + +tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" +} + +additional_tag_map = { + propagate_at_launch = "true" +} diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/autoscalinggroup/context.tf b/.terraform/modules/datadog-integration.lambda_label/examples/autoscalinggroup/context.tf new file mode 100755 index 0000000..b97f05f --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/autoscalinggroup/context.tf @@ -0,0 +1,216 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/autoscalinggroup/main.tf b/.terraform/modules/datadog-integration.lambda_label/examples/autoscalinggroup/main.tf new file mode 100755 index 0000000..f0d3aa6 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/autoscalinggroup/main.tf @@ -0,0 +1,104 @@ +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + + context = module.this.context +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template { + id = aws_launch_template.default.id + version = "$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} + +################################ +# Provider # +################################ +provider "aws" { + region = "eu-west-1" + + # Make it faster by skipping unneeded checks here + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +############################################################## +# Data sources to get VPC, subnets and security group details +############################################################## +data "aws_vpc" "default" { + default = true +} + +data "aws_subnet_ids" "all" { + vpc_id = data.aws_vpc.default.id +} + +data "aws_security_group" "default" { + vpc_id = data.aws_vpc.default.id + name = "default" +} + +data "aws_ami" "amazon_linux" { + most_recent = true + + owners = ["amazon"] + + filter { + name = "name" + + values = [ + "amzn-ami-hvm-*-x86_64-gp2", + ] + } + + filter { + name = "owner-alias" + + values = [ + "amazon", + ] + } +} + diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/autoscalinggroup/outputs.tf b/.terraform/modules/datadog-integration.lambda_label/examples/autoscalinggroup/outputs.tf new file mode 100755 index 0000000..f8fcce5 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/autoscalinggroup/outputs.tf @@ -0,0 +1,12 @@ +# terraform-null-label example used here: Output list of tags applied in each format +output "tags_as_list_of_maps" { + value = module.label.tags_as_list_of_maps +} + +output "tags" { + value = module.label.tags +} + +output "id" { + value = module.label.id +} diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/autoscalinggroup/versions.tf b/.terraform/modules/datadog-integration.lambda_label/examples/autoscalinggroup/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/autoscalinggroup/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/complete/complete.auto.tfvars b/.terraform/modules/datadog-integration.lambda_label/examples/complete/complete.auto.tfvars new file mode 100755 index 0000000..e7bc519 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/complete/complete.auto.tfvars @@ -0,0 +1,10 @@ +namespace = "cp" +environment = "uw2" +stage = "prd" +name = "null-label" + +delimiter = "" +id_length_limit = 6 + +label_key_case = "lower" +label_value_case = "upper" diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/complete/context.tf b/.terraform/modules/datadog-integration.lambda_label/examples/complete/context.tf new file mode 100755 index 0000000..973d4dc --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/complete/context.tf @@ -0,0 +1,217 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/complete/label1.tf b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label1.tf new file mode 100755 index 0000000..8da353b --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label1.tf @@ -0,0 +1,42 @@ +module "label1" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label1" { + value = { + id = module.label1.id + name = module.label1.name + namespace = module.label1.namespace + stage = module.label1.stage + attributes = module.label1.attributes + delimiter = module.label1.delimiter + } +} + +output "label1_tags" { + value = module.label1.tags +} + +output "label1_context" { + value = module.label1.context +} + +output "label1_normalized_context" { + value = module.label1.normalized_context +} + + + diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/complete/label1t1.tf b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label1t1.tf new file mode 100755 index 0000000..2bcb362 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label1t1.tf @@ -0,0 +1,18 @@ +module "label1t1" { + source = "../../" + + id_length_limit = 28 + + context = module.label1.context +} + +output "label1t1" { + value = { + id = module.label1t1.id + id_full = module.label1t1.id_full + } +} + +output "label1t1_tags" { + value = module.label1t1.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/complete/label1t2.tf b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label1t2.tf new file mode 100755 index 0000000..5df651e --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label1t2.tf @@ -0,0 +1,18 @@ +module "label1t2" { + source = "../../" + + id_length_limit = 29 + + context = module.label1.context +} + +output "label1t2" { + value = { + id = module.label1t2.id + id_full = module.label1t2.id_full + } +} + +output "label1t2_tags" { + value = module.label1t2.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/complete/label2.tf b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label2.tf new file mode 100755 index 0000000..faf7450 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label2.tf @@ -0,0 +1,42 @@ +module "label2" { + source = "../../" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + regex_replace_chars = "/[^a-zA-Z0-9-+]/" + + additional_tag_map = { + propagate_at_launch = "true" + additional_tag = "yes" + } + + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +output "label2" { + value = { + id = module.label2.id + name = module.label2.name + namespace = module.label2.namespace + stage = module.label2.stage + attributes = module.label2.attributes + delimiter = module.label2.delimiter + } +} + +output "label2_tags" { + value = module.label2.tags +} + +output "label2_tags_as_list_of_maps" { + value = module.label2.tags_as_list_of_maps +} + +output "label2_context" { + value = module.label2.context +} diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/complete/label3c.tf b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label3c.tf new file mode 100755 index 0000000..338a636 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label3c.tf @@ -0,0 +1,36 @@ +module "label3c" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3c" { + value = { + id = module.label3c.id + name = module.label3c.name + namespace = module.label3c.namespace + stage = module.label3c.stage + attributes = module.label3c.attributes + delimiter = module.label3c.delimiter + } +} + +output "label3c_tags" { + value = module.label3c.tags +} + +output "label3c_context" { + value = module.label3c.context +} + +output "label3c_normalized_context" { + value = module.label3c.normalized_context +} diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/complete/label3n.tf b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label3n.tf new file mode 100755 index 0000000..ca51282 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label3n.tf @@ -0,0 +1,36 @@ +module "label3n" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.normalized_context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3n" { + value = { + id = module.label3n.id + name = module.label3n.name + namespace = module.label3n.namespace + stage = module.label3n.stage + attributes = module.label3n.attributes + delimiter = module.label3n.delimiter + } +} + +output "label3n_tags" { + value = module.label3n.tags +} + +output "label3n_context" { + value = module.label3n.context +} + +output "label3n_normalized_context" { + value = module.label3n.normalized_context +} diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/complete/label4.tf b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label4.tf new file mode 100755 index 0000000..74e3ca1 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label4.tf @@ -0,0 +1,34 @@ +module "label4" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + name = "Example Cluster" + attributes = ["big", "fat", "honking", "cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label4" { + value = { + id = module.label4.id + name = module.label4.name + namespace = module.label4.namespace + stage = module.label4.stage + attributes = module.label4.attributes + delimiter = module.label4.delimiter + } +} + +output "label4_tags" { + value = module.label4.tags +} + +output "label4_context" { + value = module.label4.context +} diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/complete/label5.tf b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label5.tf new file mode 100755 index 0000000..0f0a76e --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label5.tf @@ -0,0 +1,33 @@ +module "label5" { + source = "../../" + enabled = false + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + } +} + +output "label5" { + value = { + id = module.label5.id + name = module.label5.name + namespace = module.label5.namespace + stage = module.label5.stage + attributes = module.label5.attributes + delimiter = module.label5.delimiter + } +} + +output "label5_tags" { + value = module.label5.tags +} + +output "label5_context" { + value = module.label5.context +} diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/complete/label6f.tf b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label6f.tf new file mode 100755 index 0000000..1ce1bab --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label6f.tf @@ -0,0 +1,20 @@ +module "label6f" { + source = "../../" + + delimiter = "~" + id_length_limit = 0 + + # Use values from tfvars + context = module.this.context +} + +output "label6f" { + value = { + id = module.label6f.id + id_full = module.label6f.id_full + } +} + +output "label6f_tags" { + value = module.label6f.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/complete/label6t.tf b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label6t.tf new file mode 100755 index 0000000..b5d9bc1 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label6t.tf @@ -0,0 +1,19 @@ +module "label6t" { + source = "../../" + + # Use values from tfvars, + # specifically: complete.auto.tfvars + context = module.this.context +} + +output "label6t" { + value = { + id = module.label6t.id + id_full = module.label6t.id_full + id_length_limit = module.this.context.id_length_limit + } +} + +output "label6t_tags" { + value = module.label6t.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/complete/label7.tf b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label7.tf new file mode 100755 index 0000000..bb365d4 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label7.tf @@ -0,0 +1,44 @@ +module "label7a" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + } +} + +module "label7" { + source = "../../" + + attributes = ["nodegroup"] + + context = module.label7a.context +} + + +output "label7" { + value = { + id = module.label7.id + name = module.label7.name + namespace = module.label7.namespace + stage = module.label7.stage + attributes = module.label7.attributes + delimiter = module.label7.delimiter + } +} + +output "label7_id" { + value = module.label7.id +} + +output "label7_attributes" { + value = module.label7.attributes +} + +output "label7_context" { + value = module.label7.context +} diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/complete/label8d.tf b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label8d.tf new file mode 100755 index 0000000..4252419 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label8d.tf @@ -0,0 +1,44 @@ +module "label8d" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8d_context" { + source = "../../" + + context = module.label8d.context +} + +output "label8d_context_id" { + value = module.label8d_context.id +} + +output "label8d_context_context" { + value = module.label8d_context.context +} + +output "label8d_context_tags" { + value = module.label8d_context.tags +} + +output "label8d_id" { + value = module.label8d.id +} + +output "label8d_context" { + value = module.label8d.context +} + +output "label8d_tags" { + value = module.label8d.tags +} diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/complete/label8dcd.tf b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label8dcd.tf new file mode 100755 index 0000000..ccdae21 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label8dcd.tf @@ -0,0 +1,24 @@ +module "label8dcd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "x" +} + +module "label8dcd_context" { + source = "../../" + + context = module.label8dcd.context +} + +output "label8dcd_context_id" { + value = module.label8dcd_context.id +} + +output "label8dcd_id" { + value = module.label8dcd.id +} diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/complete/label8dnd.tf b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label8dnd.tf new file mode 100755 index 0000000..2edb378 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label8dnd.tf @@ -0,0 +1,24 @@ +module "label8dnd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "" +} + +module "label8dnd_context" { + source = "../../" + + context = module.label8dnd.context +} + +output "label8dnd_context_id" { + value = module.label8dnd_context.id +} + +output "label8dnd_id" { + value = module.label8dnd.id +} diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/complete/label8l.tf b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label8l.tf new file mode 100755 index 0000000..7462f9e --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label8l.tf @@ -0,0 +1,46 @@ +module "label8l" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "lower" + label_value_case = "lower" + + tags = { + "kubernetes.io/cluster/" = "shared" + "upperTEST" = "testUPPER" + } +} + +module "label8l_context" { + source = "../../" + + context = module.label8l.context +} + +output "label8l_context_id" { + value = module.label8l_context.id +} + +output "label8l_context_context" { + value = module.label8l_context.context +} + +output "label8l_context_tags" { + value = module.label8l_context.tags +} + +output "label8l_id" { + value = module.label8l.id +} + +output "label8l_context" { + value = module.label8l.context +} + +output "label8l_tags" { + value = module.label8l.tags +} diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/complete/label8n.tf b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label8n.tf new file mode 100755 index 0000000..fd4ad57 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label8n.tf @@ -0,0 +1,45 @@ +module "label8n" { + source = "../../" + + enabled = true + namespace = "EG" + environment = "demo" + name = "blue" + attributes = ["eks", "ClusteR"] + delimiter = "-" + label_value_case = "none" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8n_context" { + source = "../../" + + context = module.label8n.context +} + +output "label8n_context_id" { + value = module.label8n_context.id +} + +output "label8n_context_context" { + value = module.label8n_context.context +} + +output "label8n_context_tags" { + value = module.label8n_context.tags +} + +output "label8n_id" { + value = module.label8n.id +} + +output "label8n_context" { + value = module.label8n.context +} + +output "label8n_tags" { + value = module.label8n.tags +} diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/complete/label8t.tf b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label8t.tf new file mode 100755 index 0000000..cb54c7a --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label8t.tf @@ -0,0 +1,45 @@ +module "label8t" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["EKS", "cluster"] + delimiter = "-" + label_key_case = "title" + label_value_case = "title" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8t_context" { + source = "../../" + + context = module.label8t.context +} + +output "label8t_context_id" { + value = module.label8t_context.id +} + +output "label8t_context_context" { + value = module.label8t_context.context +} + +output "label8t_context_tags" { + value = module.label8t_context.tags +} + +output "label8t_id" { + value = module.label8t.id +} + +output "label8t_context" { + value = module.label8t.context +} + +output "label8t_tags" { + value = module.label8t.tags +} diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/complete/label8u.tf b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label8u.tf new file mode 100755 index 0000000..499535b --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/complete/label8u.tf @@ -0,0 +1,50 @@ +module "label8u" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "upper" + label_value_case = "upper" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8u_context" { + source = "../../" + + context = module.label8u.context +} + +output "label8u_context_id" { + value = module.label8u_context.id +} + +output "label8u_context_context" { + value = module.label8u_context.context +} + +// debug +output "label8u_context_normalized_context" { + value = module.label8u_context.normalized_context +} + +output "label8u_context_tags" { + value = module.label8u_context.tags +} + +output "label8u_id" { + value = module.label8u.id +} + +output "label8u_context" { + value = module.label8u.context +} + +output "label8u_tags" { + value = module.label8u.tags +} diff --git a/.terraform/modules/datadog-integration.lambda_label/examples/complete/versions.tf b/.terraform/modules/datadog-integration.lambda_label/examples/complete/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/examples/complete/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog-integration.lambda_label/exports/context.tf b/.terraform/modules/datadog-integration.lambda_label/exports/context.tf new file mode 100755 index 0000000..81f99b4 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/exports/context.tf @@ -0,0 +1,202 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog-integration.lambda_label/main.tf b/.terraform/modules/datadog-integration.lambda_label/main.tf new file mode 100755 index 0000000..0deda2b --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/main.tf @@ -0,0 +1,146 @@ +locals { + + defaults = { + label_order = ["namespace", "environment", "stage", "name", "attributes"] + regex_replace_chars = "/[^-a-zA-Z0-9]/" + delimiter = "-" + replacement = "" + id_length_limit = 0 + id_hash_length = 5 + label_key_case = "title" + label_value_case = "lower" + } + + # So far, we have decided not to allow overriding replacement or id_hash_length + replacement = local.defaults.replacement + id_hash_length = local.defaults.id_hash_length + + # The values provided by variables supersede the values inherited from the context object, + # except for tags and attributes which are merged. + input = { + # It would be nice to use coalesce here, but we cannot, because it + # is an error for all the arguments to coalesce to be empty. + enabled = var.enabled == null ? var.context.enabled : var.enabled + namespace = var.namespace == null ? var.context.namespace : var.namespace + environment = var.environment == null ? var.context.environment : var.environment + stage = var.stage == null ? var.context.stage : var.stage + name = var.name == null ? var.context.name : var.name + delimiter = var.delimiter == null ? var.context.delimiter : var.delimiter + # modules tack on attributes (passed by var) to the end of the list (passed by context) + attributes = compact(distinct(concat(coalesce(var.context.attributes, []), coalesce(var.attributes, [])))) + tags = merge(var.context.tags, var.tags) + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + label_order = var.label_order == null ? var.context.label_order : var.label_order + regex_replace_chars = var.regex_replace_chars == null ? var.context.regex_replace_chars : var.regex_replace_chars + id_length_limit = var.id_length_limit == null ? var.context.id_length_limit : var.id_length_limit + label_key_case = var.label_key_case == null ? lookup(var.context, "label_key_case", null) : var.label_key_case + label_value_case = var.label_value_case == null ? lookup(var.context, "label_value_case", null) : var.label_value_case + } + + + enabled = local.input.enabled + regex_replace_chars = coalesce(local.input.regex_replace_chars, local.defaults.regex_replace_chars) + + # string_label_names are names of inputs that are strings (not list of strings) used as labels + string_label_names = ["name", "namespace", "environment", "stage"] + normalized_labels = { for k in local.string_label_names : k => + local.input[k] == null ? "" : replace(local.input[k], local.regex_replace_chars, local.replacement) + } + normalized_attributes = compact(distinct([for v in local.input.attributes : replace(v, local.regex_replace_chars, local.replacement)])) + + formatted_labels = { for k in local.string_label_names : k => local.label_value_case == "none" ? local.normalized_labels[k] : + local.label_value_case == "title" ? title(lower(local.normalized_labels[k])) : + local.label_value_case == "upper" ? upper(local.normalized_labels[k]) : lower(local.normalized_labels[k]) + } + + attributes = compact(distinct([ + for v in local.normalized_attributes : (local.label_value_case == "none" ? v : + local.label_value_case == "title" ? title(lower(v)) : + local.label_value_case == "upper" ? upper(v) : lower(v)) + ])) + + name = local.formatted_labels["name"] + namespace = local.formatted_labels["namespace"] + environment = local.formatted_labels["environment"] + stage = local.formatted_labels["stage"] + + delimiter = local.input.delimiter == null ? local.defaults.delimiter : local.input.delimiter + label_order = local.input.label_order == null ? local.defaults.label_order : coalescelist(local.input.label_order, local.defaults.label_order) + id_length_limit = local.input.id_length_limit == null ? local.defaults.id_length_limit : local.input.id_length_limit + label_key_case = local.input.label_key_case == null ? local.defaults.label_key_case : local.input.label_key_case + label_value_case = local.input.label_value_case == null ? local.defaults.label_value_case : local.input.label_value_case + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + + tags = merge(local.generated_tags, local.input.tags) + + tags_as_list_of_maps = flatten([ + for key in keys(local.tags) : merge( + { + key = key + value = local.tags[key] + }, var.additional_tag_map) + ]) + + tags_context = { + # For AWS we need `Name` to be disambiguated since it has a special meaning + name = local.id + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = local.id_context.attributes + } + + generated_tags = { + for l in keys(local.tags_context) : + local.label_key_case == "upper" ? upper(l) : ( + local.label_key_case == "lower" ? lower(l) : title(lower(l)) + ) => local.tags_context[l] if length(local.tags_context[l]) > 0 + } + + id_context = { + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = join(local.delimiter, local.attributes) + } + + labels = [for l in local.label_order : local.id_context[l] if length(local.id_context[l]) > 0] + + id_full = join(local.delimiter, local.labels) + # Create a truncated ID if needed + delimiter_length = length(local.delimiter) + # Calculate length of normal part of ID, leaving room for delimiter and hash + id_truncated_length_limit = local.id_length_limit - (local.id_hash_length + local.delimiter_length) + # Truncate the ID and ensure a single (not double) trailing delimiter + id_truncated = local.id_truncated_length_limit <= 0 ? "" : "${trimsuffix(substr(local.id_full, 0, local.id_truncated_length_limit), local.delimiter)}${local.delimiter}" + # Support usages that disallow numeric characters. Would prefer tr 0-9 q-z but Terraform does not support it. + id_hash_plus = "${md5(local.id_full)}qrstuvwxyz" + id_hash_case = local.label_value_case == "title" ? title(local.id_hash_plus) : local.label_value_case == "upper" ? upper(local.id_hash_plus) : local.label_value_case == "lower" ? lower(local.id_hash_plus) : local.id_hash_plus + id_hash = replace(local.id_hash_case, local.regex_replace_chars, local.replacement) + # Create the short ID by adding a hash to the end of the truncated ID + id_short = substr("${local.id_truncated}${local.id_hash}", 0, local.id_length_limit) + id = local.id_length_limit != 0 && length(local.id_full) > local.id_length_limit ? local.id_short : local.id_full + + + # Context of this label to pass to other label modules + output_context = { + enabled = local.enabled + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + delimiter = local.delimiter + attributes = local.attributes + tags = local.tags + additional_tag_map = local.additional_tag_map + label_order = local.label_order + regex_replace_chars = local.regex_replace_chars + id_length_limit = local.id_length_limit + label_key_case = local.label_key_case + label_value_case = local.label_value_case + } + +} diff --git a/.terraform/modules/datadog-integration.lambda_label/outputs.tf b/.terraform/modules/datadog-integration.lambda_label/outputs.tf new file mode 100755 index 0000000..87ad1be --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/outputs.tf @@ -0,0 +1,88 @@ +output "id" { + value = local.enabled ? local.id : "" + description = "Disambiguated ID restricted to `id_length_limit` characters in total" +} + +output "id_full" { + value = local.enabled ? local.id_full : "" + description = "Disambiguated ID not restricted in length" +} + +output "enabled" { + value = local.enabled + description = "True if module is enabled, false otherwise" +} + +output "namespace" { + value = local.enabled ? local.namespace : "" + description = "Normalized namespace" +} + +output "environment" { + value = local.enabled ? local.environment : "" + description = "Normalized environment" +} + +output "name" { + value = local.enabled ? local.name : "" + description = "Normalized name" +} + +output "stage" { + value = local.enabled ? local.stage : "" + description = "Normalized stage" +} + +output "delimiter" { + value = local.enabled ? local.delimiter : "" + description = "Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes`" +} + +output "attributes" { + value = local.enabled ? local.attributes : [] + description = "List of attributes" +} + +output "tags" { + value = local.enabled ? local.tags : {} + description = "Normalized Tag map" +} + +output "additional_tag_map" { + value = local.additional_tag_map + description = "The merged additional_tag_map" +} + +output "label_order" { + value = local.label_order + description = "The naming order actually used to create the ID" +} + +output "regex_replace_chars" { + value = local.regex_replace_chars + description = "The regex_replace_chars actually used to create the ID" +} + +output "id_length_limit" { + value = local.id_length_limit + description = "The id_length_limit actually used to create the ID, with `0` meaning unlimited" +} + +output "tags_as_list_of_maps" { + value = local.tags_as_list_of_maps + description = "Additional tags as a list of maps, which can be used in several AWS resources" +} + +output "normalized_context" { + value = local.output_context + description = "Normalized context of this module" +} + +output "context" { + value = local.input + description = <<-EOT + Merged but otherwise unmodified input to this module, to be used as context input to other modules. + Note: this version will have null values as defaults, not the values actually used as defaults. +EOT +} + diff --git a/.terraform/modules/datadog-integration.lambda_label/test/Makefile b/.terraform/modules/datadog-integration.lambda_label/test/Makefile new file mode 100755 index 0000000..ea15d62 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/test/Makefile @@ -0,0 +1,43 @@ +TEST_HARNESS ?= https://github.com/cloudposse/test-harness.git +TEST_HARNESS_BRANCH ?= master +TEST_HARNESS_PATH = $(realpath .test-harness) +BATS_ARGS ?= --tap +BATS_LOG ?= test.log + +# Define a macro to run the tests +define RUN_TESTS +@echo "Running tests in $(1)" +@cd $(1) && bats $(BATS_ARGS) $(addsuffix .bats,$(addprefix $(TEST_HARNESS_PATH)/test/terraform/,$(TESTS))) +endef + +default: all + +-include Makefile.* + +## Provision the test-harnesss +.test-harness: + [ -d $@ ] || git clone --depth=1 -b $(TEST_HARNESS_BRANCH) $(TEST_HARNESS) $@ + +## Initialize the tests +init: .test-harness + +## Install all dependencies (OS specific) +deps:: + @exit 0 + +## Clean up the test harness +clean: + [ "$(TEST_HARNESS_PATH)" == "/" ] || rm -rf $(TEST_HARNESS_PATH) + +## Run all tests +all: module examples/complete + +## Run basic sanity checks against the module itself +module: export TESTS ?= installed lint get-modules module-pinning get-plugins provider-pinning validate terraform-docs input-descriptions output-descriptions +module: deps + $(call RUN_TESTS, ../) + +## Run tests against example +examples/complete: export TESTS ?= installed lint get-modules get-plugins validate init plan apply +examples/complete: deps + $(call RUN_TESTS, ../$@) diff --git a/.terraform/modules/datadog-integration.lambda_label/test/Makefile.alpine b/.terraform/modules/datadog-integration.lambda_label/test/Makefile.alpine new file mode 100755 index 0000000..7925b18 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/test/Makefile.alpine @@ -0,0 +1,5 @@ +ifneq (,$(wildcard /sbin/apk)) +## Install all dependencies for alpine +deps:: init + @apk add --update terraform-docs@cloudposse json2hcl@cloudposse +endif diff --git a/.terraform/modules/datadog-integration.lambda_label/test/src/Makefile b/.terraform/modules/datadog-integration.lambda_label/test/src/Makefile new file mode 100755 index 0000000..b772822 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/test/src/Makefile @@ -0,0 +1,30 @@ +export TF_CLI_ARGS_init ?= -get-plugins=true +export TERRAFORM_VERSION ?= $(shell curl -s https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r -M '.current_version' | cut -d. -f1-2) + +.DEFAULT_GOAL : all +.PHONY: all + +## Default target +all: test + +.PHONY : init +## Initialize tests +init: + @exit 0 + +.PHONY : test +## Run tests +test: init + go mod download + go test -v -timeout 60m -run TestExamplesComplete + +## Run tests in docker container +docker/test: + docker run --name terratest --rm -it -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e GITHUB_TOKEN \ + -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" \ + -v $(CURDIR)/../../:/module/ cloudposse/test-harness:latest -C /module/test/src test + +.PHONY : clean +## Clean up files +clean: + rm -rf ../../examples/complete/*.tfstate* diff --git a/.terraform/modules/datadog-integration.lambda_label/test/src/examples_complete_test.go b/.terraform/modules/datadog-integration.lambda_label/test/src/examples_complete_test.go new file mode 100755 index 0000000..156e293 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/test/src/examples_complete_test.go @@ -0,0 +1,293 @@ +package test + +import ( + "fmt" + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" + "github.com/qdm12/reprint" + "github.com/stretchr/testify/assert" +) + +type NLContext struct { + AdditionalTagMap map[string]string `json:"additional_tag_map"` + Attributes []string `json:"attributes"` + Delimiter interface{} `json:"delimiter"` + Enabled bool `json:"enabled"` + Environment interface{} `json:"environment"` + LabelOrder []string `json:"label_order"` + Name interface{} `json:"name"` + Namespace interface{} `json:"namespace"` + RegexReplaceChars interface{} `json:"regex_replace_chars"` + Stage interface{} `json:"stage"` + Tags map[string]string `json:"tags"` +} + +// Test the Terraform module in examples/complete using Terratest. +func TestExamplesComplete(t *testing.T) { + t.Parallel() + + terraformOptions := &terraform.Options{ + // The path to where our Terraform code is located + TerraformDir: "../../examples/complete", + Upgrade: true, + } + + // At the end of the test, run `terraform destroy` to clean up any resources that were created + defer terraform.Destroy(t, terraformOptions) + + // This will run `terraform init` and `terraform apply` and fail the test if there are any errors + terraform.InitAndApply(t, terraformOptions) + + expectedLabel1Context := NLContext{ + Enabled: true, + Namespace: "CloudPosse", + Environment: "UAT", + Stage: "build", + Name: "Winston Churchroom", + Attributes: []string{"fire", "water", "earth", "air"}, + Delimiter: "-", + LabelOrder: []string{"name", "environment", "stage", "attributes"}, + Tags: map[string]string{ + "City": "Dublin", + "Environment": "Private", + }, + AdditionalTagMap: map[string]string{}, + } + + var expectedLabel1NormalizedContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel1NormalizedContext) + expectedLabel1NormalizedContext.Namespace = "cloudposse" + expectedLabel1NormalizedContext.Environment = "uat" + expectedLabel1NormalizedContext.Name = "winstonchurchroom" + expectedLabel1NormalizedContext.RegexReplaceChars = "/[^-a-zA-Z0-9]/" + expectedLabel1NormalizedContext.Tags = map[string]string{ + "City": "Dublin", + "Environment": "Private", + "Namespace": "cloudposse", + "Stage": "build", + "Name": "winstonchurchroom-uat-build-fire-water-earth-air", + "Attributes": "fire-water-earth-air", + } + + var label1NormalizedContext, label1Context NLContext + // Run `terraform output` to get the value of an output variable + label1 := terraform.OutputMap(t, terraformOptions, "label1") + label1Tags := terraform.OutputMap(t, terraformOptions, "label1_tags") + terraform.OutputStruct(t, terraformOptions, "label1_normalized_context", &label1NormalizedContext) + terraform.OutputStruct(t, terraformOptions, "label1_context", &label1Context) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1["id"]) + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1Tags["Name"]) + assert.Equal(t, "Dublin", label1Tags["City"]) + assert.Equal(t, "Private", label1Tags["Environment"]) + assert.Equal(t, expectedLabel1NormalizedContext, label1NormalizedContext) + assert.Equal(t, expectedLabel1Context, label1Context) + + label1t1 := terraform.OutputMap(t, terraformOptions, "label1t1") + label1t1Tags := terraform.OutputMap(t, terraformOptions, "label1t1_tags") + assert.Equal(t, "winstonchurchroom-uat-6a0b34", label1t1["id"], + "Extra hash character should be added when trailing delimiter is removed") + assert.Equal(t, label1["id"], label1t1["id_full"], "id_full should not be truncated") + assert.Equal(t, label1t1["id"], label1t1Tags["Name"], "Name tag should match ID") + + label1t2 := terraform.OutputMap(t, terraformOptions, "label1t2") + label1t2Tags := terraform.OutputMap(t, terraformOptions, "label1t2_tags") + assert.Equal(t, "winstonchurchroom-uat-b-6a0b3", label1t2["id"]) + assert.Equal(t, label1t2["id"], label1t2Tags["Name"], "Name tag should match ID") + + // Run `terraform output` to get the value of an output variable + label2 := terraform.OutputMap(t, terraformOptions, "label2") + label2Tags := terraform.OutputMap(t, terraformOptions, "label2_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2["id"]) + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2Tags["Name"]) + assert.Equal(t, "London", label2Tags["City"]) + assert.Equal(t, "Public", label2Tags["Environment"]) + + var expectedLabel3cContext, label3cContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel3cContext) + expectedLabel3cContext.Name = "Starfish" + expectedLabel3cContext.Stage = "release" + expectedLabel3cContext.Delimiter = "." + expectedLabel3cContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3cContext.Tags["Eat"] = "Carrot" + expectedLabel3cContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3c := terraform.OutputMap(t, terraformOptions, "label3c") + label3cTags := terraform.OutputMap(t, terraformOptions, "label3c_tags") + terraform.OutputStruct(t, terraformOptions, "label3c_context", &label3cContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3c["id"]) + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3cTags["Name"]) + assert.Equal(t, expectedLabel3cContext, label3cContext) + + var expectedLabel3nContext, label3nContext NLContext + _ = reprint.FromTo(&expectedLabel1NormalizedContext, &expectedLabel3nContext) + expectedLabel3nContext.Name = "Starfish" + expectedLabel3nContext.Stage = "release" + expectedLabel3nContext.Delimiter = "." + expectedLabel3nContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3nContext.Tags["Eat"] = "Carrot" + expectedLabel3nContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3n := terraform.OutputMap(t, terraformOptions, "label3n") + label3nTags := terraform.OutputMap(t, terraformOptions, "label3n_tags") + terraform.OutputStruct(t, terraformOptions, "label3n_context", &label3nContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3n["id"]) + assert.Equal(t, label1Tags["Name"], label3nTags["Name"], + "Tag from label1 normalized context should overwrite label3n generated tag") + assert.Equal(t, expectedLabel3nContext, label3nContext) + + // Run `terraform output` to get the value of an output variable + label4 := terraform.OutputMap(t, terraformOptions, "label4") + label4Tags := terraform.OutputMap(t, terraformOptions, "label4_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4["id"]) + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4Tags["Name"]) + + // Run `terraform output` to get the value of an output variable + label5 := terraform.OutputMap(t, terraformOptions, "label5") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "", label5["id"]) + + label6f := terraform.OutputMap(t, terraformOptions, "label6f") + label6fTags := terraform.OutputMap(t, terraformOptions, "label6f_tags") + // Test of setting var.label_key_case = "lower", var.label_value_case = "upper" + assert.Equal(t, "CP~UW2~PRD~NULL-LABEL", label6f["id_full"]) + assert.Equal(t, label6f["id_full"], label6f["id"], "id should not be truncated") + assert.Equal(t, label6f["id"], label6fTags["name"], "Name tag should match ID") + + label6t := terraform.OutputMap(t, terraformOptions, "label6t") + label6tTags := terraform.OutputMap(t, terraformOptions, "label6t_tags") + assert.Equal(t, "CPUW2PRDNULL-LABEL", label6t["id_full"]) + assert.NotEqual(t, label6t["id_full"], label6t["id"], "id should be truncated") + assert.Equal(t, label6t["id"], label6tTags["name"], "Name tag should match ID") + assert.Equal(t, label6t["id_length_limit"], fmt.Sprintf("%d", len(label6t["id"])), + "Truncated ID length should equal length limit") + + label7 := terraform.OutputMap(t, terraformOptions, "label7") + assert.Equal(t, "eg-demo-blue-cluster-nodegroup", label7["id"], "var.attributes should be appended after context.attributes") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter=""` returns expected value of id, context id + label8dndID := terraform.Output(t, terraformOptions, "label8dnd_id") + label8dndContextID := terraform.Output(t, terraformOptions, "label8dnd_context_id") + assert.Equal(t, "egdemobluecluster", label8dndID) + assert.Equal(t, label8dndID, label8dndContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter="x"` returns expected value of id, context id + label8dcdID := terraform.Output(t, terraformOptions, "label8dcd_id") + label8dcdContextID := terraform.Output(t, terraformOptions, "label8dcd_context_id") + assert.Equal(t, "egxdemoxbluexcluster", label8dcdID) + assert.Equal(t, label8dcdID, label8dcdContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=lower` returns expected values of id, tags, context tags + label8dExpectedTags := map[string]string{ + "Attributes": "cluster", + "Environment": "demo", + "Name": "eg-demo-blue-cluster", + "Namespace": "eg", + "kubernetes.io/cluster/": "shared", + } + + label8dID := terraform.Output(t, terraformOptions, "label8d_id") + label8dContextID := terraform.Output(t, terraformOptions, "label8d_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8dID) + assert.Equal(t, label8dID, label8dContextID, "ID and context ID should be equal") + + label8dTags := terraform.OutputMap(t, terraformOptions, "label8d_tags") + label8dContextTags := terraform.OutputMap(t, terraformOptions, "label8d_context_tags") + + assert.Exactly(t, label8dExpectedTags, label8dTags, "generated tags are different from expected") + assert.Exactly(t, label8dTags, label8dContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=lower` and `label_value_case=lower` returns expected values of id, tags, context tags + label8lExpectedTags := map[string]string{ + "attributes": "cluster", + "environment": "demo", + "name": "eg-demo-blue-cluster", + "namespace": "eg", + "kubernetes.io/cluster/": "shared", + "upperTEST": "testUPPER", + } + + label8lID := terraform.Output(t, terraformOptions, "label8l_id") + label8lContextID := terraform.Output(t, terraformOptions, "label8l_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8lID) + assert.Equal(t, label8lID, label8lContextID, "ID and context ID should be equal") + + label8lTags := terraform.OutputMap(t, terraformOptions, "label8l_tags") + label8lContextTags := terraform.OutputMap(t, terraformOptions, "label8l_context_tags") + + assert.Exactly(t, label8lExpectedTags, label8lTags, "generated tags are different from expected") + assert.Exactly(t, label8lTags, label8lContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=title` returns expected values of id, tags, context tags + label8tExpectedTags := map[string]string{ + "Attributes": "Eks-Cluster", + "Environment": "Demo", + "Name": "Eg-Demo-Blue-Eks-Cluster", + "Namespace": "Eg", + "kubernetes.io/cluster/": "shared", + } + + label8tID := terraform.Output(t, terraformOptions, "label8t_id") + label8tContextID := terraform.Output(t, terraformOptions, "label8t_context_id") + assert.Equal(t, "Eg-Demo-Blue-Eks-Cluster", label8tID) + assert.Equal(t, label8tID, label8tContextID, "ID and context ID should be equal") + + label8tTags := terraform.OutputMap(t, terraformOptions, "label8t_tags") + label8tContextTags := terraform.OutputMap(t, terraformOptions, "label8t_context_tags") + + assert.Exactly(t, label8tExpectedTags, label8tTags, "generated tags are different from expected") + assert.Exactly(t, label8tTags, label8tContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=upper` and `label_value_case=upper` returns expected values of id, tags, context tags + label8uExpectedTags := map[string]string{ + "ATTRIBUTES": "CLUSTER", + "ENVIRONMENT": "DEMO", + "NAME": "EG-DEMO-BLUE-CLUSTER", + "NAMESPACE": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8uID := terraform.Output(t, terraformOptions, "label8u_id") + label8uContextID := terraform.Output(t, terraformOptions, "label8u_context_id") + assert.Equal(t, "EG-DEMO-BLUE-CLUSTER", label8uID) + assert.Equal(t, label8uID, label8uContextID, "ID and context ID should be equal") + + label8uTags := terraform.OutputMap(t, terraformOptions, "label8u_tags") + label8uContextTags := terraform.OutputMap(t, terraformOptions, "label8u_context_tags") + + assert.Exactly(t, label8uExpectedTags, label8uTags, "generated tags are different from expected") + assert.Exactly(t, label8uTags, label8uContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=none` returns expected values of id, tags, context tags + label8nExpectedTags := map[string]string{ + "Attributes": "eks-ClusteR", + "Environment": "demo", + "Name": "EG-demo-blue-eks-ClusteR", + "Namespace": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8nID := terraform.Output(t, terraformOptions, "label8n_id") + label8nContextID := terraform.Output(t, terraformOptions, "label8n_context_id") + assert.Equal(t, "EG-demo-blue-eks-ClusteR", label8nID) + assert.Equal(t, label8nID, label8nContextID, "ID and context ID should be equal") + + label8nTags := terraform.OutputMap(t, terraformOptions, "label8n_tags") + label8nContextTags := terraform.OutputMap(t, terraformOptions, "label8n_context_tags") + + assert.Exactly(t, label8nExpectedTags, label8nTags, "generated tags are different from expected") + assert.Exactly(t, label8nTags, label8nContextTags, "tags and context tags should be equal") +} diff --git a/.terraform/modules/datadog-integration.lambda_label/test/src/go.mod b/.terraform/modules/datadog-integration.lambda_label/test/src/go.mod new file mode 100755 index 0000000..d866541 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/test/src/go.mod @@ -0,0 +1,9 @@ +module github.com/cloudposse/terraform-null-label + +go 1.14 + +require ( + github.com/gruntwork-io/terratest v0.31.1 + github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 + github.com/stretchr/testify v1.6.1 +) diff --git a/.terraform/modules/datadog-integration.lambda_label/test/src/go.sum b/.terraform/modules/datadog-integration.lambda_label/test/src/go.sum new file mode 100755 index 0000000..b8d46b1 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/test/src/go.sum @@ -0,0 +1,595 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= +github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.5/go.mod h1:foo3aIXRQ90zFve3r0QiDsrjGDUwWhKl0ZOQy1CT14k= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= +github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200109221225-a4f60165b7a3/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= +github.com/gruntwork-io/terratest v0.31.1 h1:MPGe/5pGgJAIZ/hb+0LM1KyJKSi/QyxSkHoP9/CBhJg= +github.com/gruntwork-io/terratest v0.31.1/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= +github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4= +github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= +github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= +k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= +k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= +k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= +k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= +k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= +k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= +k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= +modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/.terraform/modules/datadog-integration.lambda_label/variables.tf b/.terraform/modules/datadog-integration.lambda_label/variables.tf new file mode 100755 index 0000000..40fb268 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/variables.tf @@ -0,0 +1,157 @@ +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} diff --git a/.terraform/modules/datadog-integration.lambda_label/versions.tf b/.terraform/modules/datadog-integration.lambda_label/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog-integration.lambda_label/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog-integration.this/LICENSE b/.terraform/modules/datadog-integration.this/LICENSE new file mode 100755 index 0000000..c844c70 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017-2020 Cloud Posse, LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/.terraform/modules/datadog-integration.this/Makefile b/.terraform/modules/datadog-integration.this/Makefile new file mode 100755 index 0000000..97d8087 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/Makefile @@ -0,0 +1,10 @@ +SHELL := /bin/bash + +# List of targets the `readme` target should call before generating the readme +export README_DEPS ?= docs/targets.md docs/terraform.md + +-include $(shell curl -sSL -o .build-harness "https://git.io/build-harness"; echo .build-harness) + +## Lint terraform code +lint: + $(SELF) terraform/install terraform/get-modules terraform/get-plugins terraform/lint terraform/validate diff --git a/.terraform/modules/datadog-integration.this/README.md b/.terraform/modules/datadog-integration.this/README.md new file mode 100755 index 0000000..32950e4 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/README.md @@ -0,0 +1,938 @@ + +# terraform-null-label [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-null-label.svg)](https://github.com/cloudposse/terraform-null-label/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) + + +[![README Header][readme_header_img]][readme_header_link] + +[![Cloud Posse][logo]](https://cpco.io/homepage) + + + +Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + +This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. +However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). +So if you prefer the term `stage` to `environment` +you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. +- If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. +- If you want the attributes in a different order, you can specify that, too, with the `label_order` list. +- You can set a maximum length for the name, and the module will create a unique name that fits within that length. +- You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. +- The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + +It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. +For example, if you have 10 instances, there should be 10 different labels. +However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + +All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + +**NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. +With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + +- Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. +- Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. +- Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. + + +--- + +This project is part of our comprehensive ["SweetOps"](https://cpco.io/sweetops) approach towards DevOps. +[][share_email] +[][share_googleplus] +[][share_facebook] +[][share_reddit] +[][share_linkedin] +[][share_twitter] + + +[![Terraform Open Source Modules](https://docs.cloudposse.com/images/terraform-open-source-modules.svg)][terraform_modules] + + + +It's 100% Open Source and licensed under the [APACHE2](LICENSE). + + + + + + + +We literally have [*hundreds of terraform modules*][terraform_modules] that are Open Source and well-maintained. Check them out! + + + + + + + +## Security & Compliance [](https://bridgecrew.io/) + +Security scanning is graciously provided by Bridgecrew. Bridgecrew is the leading fully hosted, cloud-native solution providing continuous Terraform security and compliance. + +| Benchmark | Description | +|--------|---------------| +| [![Infrastructure Security](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/general)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=INFRASTRUCTURE+SECURITY) | Infrastructure Security Compliance | +| [![CIS KUBERNETES](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_kubernetes)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+KUBERNETES+V1.5) | Center for Internet Security, KUBERNETES Compliance | +| [![CIS AWS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_aws)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AWS+V1.2) | Center for Internet Security, AWS Compliance | +| [![CIS AZURE](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_azure)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AZURE+V1.1) | Center for Internet Security, AZURE Compliance | +| [![PCI-DSS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/pci)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=PCI-DSS+V3.2) | Payment Card Industry Data Security Standards Compliance | +| [![NIST-800-53](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/nist)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=NIST-800-53) | National Institute of Standards and Technology Compliance | +| [![ISO27001](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/iso)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=ISO27001) | Information Security Management System, ISO/IEC 27001 Compliance | +| [![SOC2](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/soc2)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=SOC2)| Service Organization Control 2 Compliance | +| [![CIS GCP](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_gcp)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+GCP+V1.1) | Center for Internet Security, GCP Compliance | +| [![HIPAA](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/hipaa)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=HIPAA) | Health Insurance Portability and Accountability Compliance | + + + +## Usage + + +**IMPORTANT:** We do not pin modules to versions in our examples because of the +difficulty of keeping the versions in the documentation in sync with the latest released versions. +We highly recommend that in your code you pin the version to the exact version you are +using so that your infrastructure remains stable, and update versions in a +systematic way so that they do not catch you by surprise. + +Also, because of a bug in the Terraform registry ([hashicorp/terraform#21417](https://github.com/hashicorp/terraform/issues/21417)), +the registry shows many of our inputs as required when in fact they are optional. +The table below correctly indicates which inputs are required. + + +### Defaults + +Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. +The context object is a single object that contains all the input values for `terraform-null-label`. +However, each input value can also be specified individually by name as a standard Terraform variable, +and the value of those variables, when set to something other than `null`, will override the value +in the context object. In order to allow chaining of these objects, where the context object input to one +module is transformed and passed to the next module, all the variables default to `null` or empty collections. +The actual default values used when nothing is explicitly set are describe in the documentation below. + +For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, +`terraform-null-label` will actually use the default delimiter `-` (hyphen). + +A non-obvious but intentional consequence of this design is that once a module sets a non-default value, +future modules in the chain cannot reset the value back to the original default. Insted, the new setting +becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, +so once a tag is added, it will remain in the tag set and cannot be removed, although its value can +be overwritten. + +### Simple Example + +```hcl +module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} +``` + +This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` +(you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + +Now reference the label when creating an instance: + +```hcl +resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags +} +``` + +Or define a security group: + +```hcl +resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} +``` + + +### Advanced Example + +Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + +```hcl +module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] +} + +module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] +} +``` + +
+ +### Advanced Example 2 + +Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + +```hcl +tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } +] +``` + +Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + +```hcl +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} +``` + +
+ +### Advanced Example 3 + +See [complete example](./examples/complete) for even more examples. + +This example shows how you can pass the `context` output of one label module to the next label_module, +allowing you to create one label that has the base set of values, and then creating every extra label +as a derivative of that. + +
Click to show + +```hcl +module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} +``` + +This creates label outputs like this: + +```hcl +label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" +} +label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } +} +label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } +} +label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" +} +label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" +} +label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } +} +label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" +} +label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, +] +label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" +} +label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } +} +label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } +} +label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" +} + +``` + +
+ + + + + + + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + + + + +## Share the Love + +Like this project? Please give it a ★ on [our GitHub](https://github.com/cloudposse/terraform-null-label)! (it helps us **a lot**) + +Are you using this project or any of our other projects? Consider [leaving a testimonial][testimonial]. =) + + +## Related Projects + +Check out these related projects. + +- [terraform-terraform-label](https://github.com/cloudposse/terraform-terraform-label) - Terraform Module to define a consistent naming convention by (namespace, environment, stage, name, [attributes]) + + + +## Help + +**Got a question?** We got answers. + +File a GitHub [issue](https://github.com/cloudposse/terraform-null-label/issues), send us an [email][email] or join our [Slack Community][slack]. + +[![README Commercial Support][readme_commercial_support_img]][readme_commercial_support_link] + +## DevOps Accelerator for Startups + + +We are a [**DevOps Accelerator**][commercial_support]. We'll help you build your cloud infrastructure from the ground up so you can own it. Then we'll show you how to operate it and stick around for as long as you need us. + +[![Learn More](https://img.shields.io/badge/learn%20more-success.svg?style=for-the-badge)][commercial_support] + +Work directly with our team of DevOps experts via email, slack, and video conferencing. + +We deliver 10x the value for a fraction of the cost of a full-time engineer. Our track record is not even funny. If you want things done right and you need it done FAST, then we're your best bet. + +- **Reference Architecture.** You'll get everything you need from the ground up built using 100% infrastructure as code. +- **Release Engineering.** You'll have end-to-end CI/CD with unlimited staging environments. +- **Site Reliability Engineering.** You'll have total visibility into your apps and microservices. +- **Security Baseline.** You'll have built-in governance with accountability and audit logs for all changes. +- **GitOps.** You'll be able to operate your infrastructure via Pull Requests. +- **Training.** You'll receive hands-on training so your team can operate what we build. +- **Questions.** You'll have a direct line of communication between our teams via a Shared Slack channel. +- **Troubleshooting.** You'll get help to triage when things aren't working. +- **Code Reviews.** You'll receive constructive feedback on Pull Requests. +- **Bug Fixes.** We'll rapidly work with you to fix any bugs in our projects. + +## Slack Community + +Join our [Open Source Community][slack] on Slack. It's **FREE** for everyone! Our "SweetOps" community is where you get to talk with others who share a similar vision for how to rollout and manage infrastructure. This is the best place to talk shop, ask questions, solicit feedback, and work together as a community to build totally *sweet* infrastructure. + +## Discourse Forums + +Participate in our [Discourse Forums][discourse]. Here you'll find answers to commonly asked questions. Most questions will be related to the enormous number of projects we support on our GitHub. Come here to collaborate on answers, find solutions, and get ideas about the products and services we value. It only takes a minute to get started! Just sign in with SSO using your GitHub account. + +## Newsletter + +Sign up for [our newsletter][newsletter] that covers everything on our technology radar. Receive updates on what we're up to on GitHub as well as awesome new projects we discover. + +## Office Hours + +[Join us every Wednesday via Zoom][office_hours] for our weekly "Lunch & Learn" sessions. It's **FREE** for everyone! + +[![zoom](https://img.cloudposse.com/fit-in/200x200/https://cloudposse.com/wp-content/uploads/2019/08/Powered-by-Zoom.png")][office_hours] + +## Contributing + +### Bug Reports & Feature Requests + +Please use the [issue tracker](https://github.com/cloudposse/terraform-null-label/issues) to report any bugs or file feature requests. + +### Developing + +If you are interested in being a contributor and want to get involved in developing this project or [help out](https://cpco.io/help-out) with our other projects, we would love to hear from you! Shoot us an [email][email]. + +In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. + + 1. **Fork** the repo on GitHub + 2. **Clone** the project to your own machine + 3. **Commit** changes to your own branch + 4. **Push** your work back up to your fork + 5. Submit a **Pull Request** so that we can review your changes + +**NOTE:** Be sure to merge the latest changes from "upstream" before making a pull request! + + +## Copyright + +Copyright © 2017-2021 [Cloud Posse, LLC](https://cpco.io/copyright) + + + +## License + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +See [LICENSE](LICENSE) for full details. + +```text +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +``` + + + + + + + + + +## Trademarks + +All other trademarks referenced herein are the property of their respective owners. + +## About + +This project is maintained and funded by [Cloud Posse, LLC][website]. Like it? Please let us know by [leaving a testimonial][testimonial]! + +[![Cloud Posse][logo]][website] + +We're a [DevOps Professional Services][hire] company based in Los Angeles, CA. We ❤️ [Open Source Software][we_love_open_source]. + +We offer [paid support][commercial_support] on all of our projects. + +Check out [our other projects][github], [follow us on twitter][twitter], [apply for a job][jobs], or [hire us][hire] to help with your cloud strategy and implementation. + + + +### Contributors + + +| [![Erik Osterman][osterman_avatar]][osterman_homepage]
[Erik Osterman][osterman_homepage] | [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]
[Andriy Knysh][aknysh_homepage] | [![Igor Rodionov][goruha_avatar]][goruha_homepage]
[Igor Rodionov][goruha_homepage] | [![Sergey Vasilyev][s2504s_avatar]][s2504s_homepage]
[Sergey Vasilyev][s2504s_homepage] | [![Michael Pereira][MichaelPereira_avatar]][MichaelPereira_homepage]
[Michael Pereira][MichaelPereira_homepage] | [![Jamie Nelson][Jamie-BitFlight_avatar]][Jamie-BitFlight_homepage]
[Jamie Nelson][Jamie-BitFlight_homepage] | [![Vladimir][SweetOps_avatar]][SweetOps_homepage]
[Vladimir][SweetOps_homepage] | [![Daren Desjardins][darend_avatar]][darend_homepage]
[Daren Desjardins][darend_homepage] | [![Maarten van der Hoef][maartenvanderhoef_avatar]][maartenvanderhoef_homepage]
[Maarten van der Hoef][maartenvanderhoef_homepage] | [![Adam Tibbing][tibbing_avatar]][tibbing_homepage]
[Adam Tibbing][tibbing_homepage] | +|---|---|---|---|---|---|---|---|---|---| + + + [osterman_homepage]: https://github.com/osterman + [osterman_avatar]: https://img.cloudposse.com/150x150/https://github.com/osterman.png + [aknysh_homepage]: https://github.com/aknysh + [aknysh_avatar]: https://img.cloudposse.com/150x150/https://github.com/aknysh.png + [goruha_homepage]: https://github.com/goruha + [goruha_avatar]: https://img.cloudposse.com/150x150/https://github.com/goruha.png + [s2504s_homepage]: https://github.com/s2504s + [s2504s_avatar]: https://img.cloudposse.com/150x150/https://github.com/s2504s.png + [MichaelPereira_homepage]: https://github.com/MichaelPereira + [MichaelPereira_avatar]: https://img.cloudposse.com/150x150/https://github.com/MichaelPereira.png + [Jamie-BitFlight_homepage]: https://github.com/Jamie-BitFlight + [Jamie-BitFlight_avatar]: https://img.cloudposse.com/150x150/https://github.com/Jamie-BitFlight.png + [SweetOps_homepage]: https://github.com/SweetOps + [SweetOps_avatar]: https://img.cloudposse.com/150x150/https://github.com/SweetOps.png + [darend_homepage]: https://github.com/darend + [darend_avatar]: https://img.cloudposse.com/150x150/https://github.com/darend.png + [maartenvanderhoef_homepage]: https://github.com/maartenvanderhoef + [maartenvanderhoef_avatar]: https://img.cloudposse.com/150x150/https://github.com/maartenvanderhoef.png + [tibbing_homepage]: https://github.com/tibbing + [tibbing_avatar]: https://img.cloudposse.com/150x150/https://github.com/tibbing.png + +[![README Footer][readme_footer_img]][readme_footer_link] +[![Beacon][beacon]][website] + + [logo]: https://cloudposse.com/logo-300x69.svg + [docs]: https://cpco.io/docs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=docs + [website]: https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=website + [github]: https://cpco.io/github?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=github + [jobs]: https://cpco.io/jobs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=jobs + [hire]: https://cpco.io/hire?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=hire + [slack]: https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=slack + [linkedin]: https://cpco.io/linkedin?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=linkedin + [twitter]: https://cpco.io/twitter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=twitter + [testimonial]: https://cpco.io/leave-testimonial?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=testimonial + [office_hours]: https://cloudposse.com/office-hours?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=office_hours + [newsletter]: https://cpco.io/newsletter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=newsletter + [discourse]: https://ask.sweetops.com/?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=discourse + [email]: https://cpco.io/email?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=email + [commercial_support]: https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=commercial_support + [we_love_open_source]: https://cpco.io/we-love-open-source?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=we_love_open_source + [terraform_modules]: https://cpco.io/terraform-modules?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=terraform_modules + [readme_header_img]: https://cloudposse.com/readme/header/img + [readme_header_link]: https://cloudposse.com/readme/header/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_header_link + [readme_footer_img]: https://cloudposse.com/readme/footer/img + [readme_footer_link]: https://cloudposse.com/readme/footer/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_footer_link + [readme_commercial_support_img]: https://cloudposse.com/readme/commercial-support/img + [readme_commercial_support_link]: https://cloudposse.com/readme/commercial-support/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_commercial_support_link + [share_twitter]: https://twitter.com/intent/tweet/?text=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_linkedin]: https://www.linkedin.com/shareArticle?mini=true&title=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_reddit]: https://reddit.com/submit/?url=https://github.com/cloudposse/terraform-null-label + [share_facebook]: https://facebook.com/sharer/sharer.php?u=https://github.com/cloudposse/terraform-null-label + [share_googleplus]: https://plus.google.com/share?url=https://github.com/cloudposse/terraform-null-label + [share_email]: mailto:?subject=terraform-null-label&body=https://github.com/cloudposse/terraform-null-label + [beacon]: https://ga-beacon.cloudposse.com/UA-76589703-4/cloudposse/terraform-null-label?pixel&cs=github&cm=readme&an=terraform-null-label diff --git a/.terraform/modules/datadog-integration.this/README.yaml b/.terraform/modules/datadog-integration.this/README.yaml new file mode 100755 index 0000000..42bdb84 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/README.yaml @@ -0,0 +1,618 @@ +name: terraform-null-label +tags: +- aws +- terraform +- terraform-modules +- naming-convention +- name +- namespace +- stage +categories: +- terraform-modules/supported +license: APACHE2 +github_repo: cloudposse/terraform-null-label +badges: +- name: Latest Release + image: https://img.shields.io/github/release/cloudposse/terraform-null-label.svg + url: https://github.com/cloudposse/terraform-null-label/releases/latest +- name: Slack Community + image: https://slack.cloudposse.com/badge.svg + url: https://slack.cloudposse.com +related: +- name: terraform-terraform-label + description: Terraform Module to define a consistent naming convention by (namespace, + environment, stage, name, [attributes]) + url: https://github.com/cloudposse/terraform-terraform-label +description: |- + Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + + This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. + However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). + So if you prefer the term `stage` to `environment` + you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. + - If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. + - If you want the attributes in a different order, you can specify that, too, with the `label_order` list. + - You can set a maximum length for the name, and the module will create a unique name that fits within that length. + - You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. + - The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + + It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. + For example, if you have 10 instances, there should be 10 different labels. + However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + + All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + + **NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. + With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + + - Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. + - Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. + - Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. +usage: |- + ### Defaults + + Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. + The context object is a single object that contains all the input values for `terraform-null-label`. + However, each input value can also be specified individually by name as a standard Terraform variable, + and the value of those variables, when set to something other than `null`, will override the value + in the context object. In order to allow chaining of these objects, where the context object input to one + module is transformed and passed to the next module, all the variables default to `null` or empty collections. + The actual default values used when nothing is explicitly set are describe in the documentation below. + + For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, + `terraform-null-label` will actually use the default delimiter `-` (hyphen). + + A non-obvious but intentional consequence of this design is that once a module sets a non-default value, + future modules in the chain cannot reset the value back to the original default. Insted, the new setting + becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, + so once a tag is added, it will remain in the tag set and cannot be removed, although its value can + be overwritten. + + ### Simple Example + + ```hcl + module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + ``` + + This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` + (you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + + Now reference the label when creating an instance: + + ```hcl + resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags + } + ``` + + Or define a security group: + + ```hcl + resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + } + ``` + + + ### Advanced Example + + Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + + ```hcl + module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] + } + + module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] + } + ``` + +
+ + ### Advanced Example 2 + + Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + + ```hcl + tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } + ] + ``` + + Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + + ```hcl + ################################ + # terraform-null-label example # + ################################ + module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } + } + + ####################### + # Launch template # + ####################### + resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } + } + + ###################### + # Autoscaling group # + ###################### + resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps + } + ``` + +
+ + ### Advanced Example 3 + + See [complete example](./examples/complete) for even more examples. + + This example shows how you can pass the `context` output of one label module to the next label_module, + allowing you to create one label that has the base set of values, and then creating every extra label + as a derivative of that. + +
Click to show + + ```hcl + module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } + } + + module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } + } + + module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } + } + ``` + + This creates label outputs like this: + + ```hcl + label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" + } + label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } + } + label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + } + label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" + } + label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } + } + label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" + } + label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, + ] + label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" + } + label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } + } + label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + } + label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + + ``` + +
+ +include: +- docs/targets.md +- docs/terraform.md +contributors: +- name: Erik Osterman + github: osterman +- name: Andriy Knysh + github: aknysh +- name: Igor Rodionov + github: goruha +- name: Sergey Vasilyev + github: s2504s +- name: Michael Pereira + github: MichaelPereira +- name: Jamie Nelson + github: Jamie-BitFlight +- name: Vladimir + github: SweetOps +- name: Daren Desjardins + github: darend +- name: Maarten van der Hoef + github: maartenvanderhoef +- name: Adam Tibbing + github: tibbing diff --git a/.terraform/modules/datadog-integration.this/docs/targets.md b/.terraform/modules/datadog-integration.this/docs/targets.md new file mode 100755 index 0000000..3dce8b3 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/docs/targets.md @@ -0,0 +1,12 @@ + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + diff --git a/.terraform/modules/datadog-integration.this/docs/terraform.md b/.terraform/modules/datadog-integration.this/docs/terraform.md new file mode 100755 index 0000000..d4f48f4 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/docs/terraform.md @@ -0,0 +1,54 @@ + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + diff --git a/.terraform/modules/datadog-integration.this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars b/.terraform/modules/datadog-integration.this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars new file mode 100755 index 0000000..f7c725f --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars @@ -0,0 +1,12 @@ +namespace = "eg" +stage = "prod" +name = "app" + +tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" +} + +additional_tag_map = { + propagate_at_launch = "true" +} diff --git a/.terraform/modules/datadog-integration.this/examples/autoscalinggroup/context.tf b/.terraform/modules/datadog-integration.this/examples/autoscalinggroup/context.tf new file mode 100755 index 0000000..b97f05f --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/autoscalinggroup/context.tf @@ -0,0 +1,216 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog-integration.this/examples/autoscalinggroup/main.tf b/.terraform/modules/datadog-integration.this/examples/autoscalinggroup/main.tf new file mode 100755 index 0000000..f0d3aa6 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/autoscalinggroup/main.tf @@ -0,0 +1,104 @@ +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + + context = module.this.context +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template { + id = aws_launch_template.default.id + version = "$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} + +################################ +# Provider # +################################ +provider "aws" { + region = "eu-west-1" + + # Make it faster by skipping unneeded checks here + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +############################################################## +# Data sources to get VPC, subnets and security group details +############################################################## +data "aws_vpc" "default" { + default = true +} + +data "aws_subnet_ids" "all" { + vpc_id = data.aws_vpc.default.id +} + +data "aws_security_group" "default" { + vpc_id = data.aws_vpc.default.id + name = "default" +} + +data "aws_ami" "amazon_linux" { + most_recent = true + + owners = ["amazon"] + + filter { + name = "name" + + values = [ + "amzn-ami-hvm-*-x86_64-gp2", + ] + } + + filter { + name = "owner-alias" + + values = [ + "amazon", + ] + } +} + diff --git a/.terraform/modules/datadog-integration.this/examples/autoscalinggroup/outputs.tf b/.terraform/modules/datadog-integration.this/examples/autoscalinggroup/outputs.tf new file mode 100755 index 0000000..f8fcce5 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/autoscalinggroup/outputs.tf @@ -0,0 +1,12 @@ +# terraform-null-label example used here: Output list of tags applied in each format +output "tags_as_list_of_maps" { + value = module.label.tags_as_list_of_maps +} + +output "tags" { + value = module.label.tags +} + +output "id" { + value = module.label.id +} diff --git a/.terraform/modules/datadog-integration.this/examples/autoscalinggroup/versions.tf b/.terraform/modules/datadog-integration.this/examples/autoscalinggroup/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/autoscalinggroup/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog-integration.this/examples/complete/complete.auto.tfvars b/.terraform/modules/datadog-integration.this/examples/complete/complete.auto.tfvars new file mode 100755 index 0000000..e7bc519 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/complete/complete.auto.tfvars @@ -0,0 +1,10 @@ +namespace = "cp" +environment = "uw2" +stage = "prd" +name = "null-label" + +delimiter = "" +id_length_limit = 6 + +label_key_case = "lower" +label_value_case = "upper" diff --git a/.terraform/modules/datadog-integration.this/examples/complete/context.tf b/.terraform/modules/datadog-integration.this/examples/complete/context.tf new file mode 100755 index 0000000..973d4dc --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/complete/context.tf @@ -0,0 +1,217 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog-integration.this/examples/complete/label1.tf b/.terraform/modules/datadog-integration.this/examples/complete/label1.tf new file mode 100755 index 0000000..8da353b --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/complete/label1.tf @@ -0,0 +1,42 @@ +module "label1" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label1" { + value = { + id = module.label1.id + name = module.label1.name + namespace = module.label1.namespace + stage = module.label1.stage + attributes = module.label1.attributes + delimiter = module.label1.delimiter + } +} + +output "label1_tags" { + value = module.label1.tags +} + +output "label1_context" { + value = module.label1.context +} + +output "label1_normalized_context" { + value = module.label1.normalized_context +} + + + diff --git a/.terraform/modules/datadog-integration.this/examples/complete/label1t1.tf b/.terraform/modules/datadog-integration.this/examples/complete/label1t1.tf new file mode 100755 index 0000000..2bcb362 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/complete/label1t1.tf @@ -0,0 +1,18 @@ +module "label1t1" { + source = "../../" + + id_length_limit = 28 + + context = module.label1.context +} + +output "label1t1" { + value = { + id = module.label1t1.id + id_full = module.label1t1.id_full + } +} + +output "label1t1_tags" { + value = module.label1t1.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.this/examples/complete/label1t2.tf b/.terraform/modules/datadog-integration.this/examples/complete/label1t2.tf new file mode 100755 index 0000000..5df651e --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/complete/label1t2.tf @@ -0,0 +1,18 @@ +module "label1t2" { + source = "../../" + + id_length_limit = 29 + + context = module.label1.context +} + +output "label1t2" { + value = { + id = module.label1t2.id + id_full = module.label1t2.id_full + } +} + +output "label1t2_tags" { + value = module.label1t2.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.this/examples/complete/label2.tf b/.terraform/modules/datadog-integration.this/examples/complete/label2.tf new file mode 100755 index 0000000..faf7450 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/complete/label2.tf @@ -0,0 +1,42 @@ +module "label2" { + source = "../../" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + regex_replace_chars = "/[^a-zA-Z0-9-+]/" + + additional_tag_map = { + propagate_at_launch = "true" + additional_tag = "yes" + } + + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +output "label2" { + value = { + id = module.label2.id + name = module.label2.name + namespace = module.label2.namespace + stage = module.label2.stage + attributes = module.label2.attributes + delimiter = module.label2.delimiter + } +} + +output "label2_tags" { + value = module.label2.tags +} + +output "label2_tags_as_list_of_maps" { + value = module.label2.tags_as_list_of_maps +} + +output "label2_context" { + value = module.label2.context +} diff --git a/.terraform/modules/datadog-integration.this/examples/complete/label3c.tf b/.terraform/modules/datadog-integration.this/examples/complete/label3c.tf new file mode 100755 index 0000000..338a636 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/complete/label3c.tf @@ -0,0 +1,36 @@ +module "label3c" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3c" { + value = { + id = module.label3c.id + name = module.label3c.name + namespace = module.label3c.namespace + stage = module.label3c.stage + attributes = module.label3c.attributes + delimiter = module.label3c.delimiter + } +} + +output "label3c_tags" { + value = module.label3c.tags +} + +output "label3c_context" { + value = module.label3c.context +} + +output "label3c_normalized_context" { + value = module.label3c.normalized_context +} diff --git a/.terraform/modules/datadog-integration.this/examples/complete/label3n.tf b/.terraform/modules/datadog-integration.this/examples/complete/label3n.tf new file mode 100755 index 0000000..ca51282 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/complete/label3n.tf @@ -0,0 +1,36 @@ +module "label3n" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.normalized_context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3n" { + value = { + id = module.label3n.id + name = module.label3n.name + namespace = module.label3n.namespace + stage = module.label3n.stage + attributes = module.label3n.attributes + delimiter = module.label3n.delimiter + } +} + +output "label3n_tags" { + value = module.label3n.tags +} + +output "label3n_context" { + value = module.label3n.context +} + +output "label3n_normalized_context" { + value = module.label3n.normalized_context +} diff --git a/.terraform/modules/datadog-integration.this/examples/complete/label4.tf b/.terraform/modules/datadog-integration.this/examples/complete/label4.tf new file mode 100755 index 0000000..74e3ca1 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/complete/label4.tf @@ -0,0 +1,34 @@ +module "label4" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + name = "Example Cluster" + attributes = ["big", "fat", "honking", "cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label4" { + value = { + id = module.label4.id + name = module.label4.name + namespace = module.label4.namespace + stage = module.label4.stage + attributes = module.label4.attributes + delimiter = module.label4.delimiter + } +} + +output "label4_tags" { + value = module.label4.tags +} + +output "label4_context" { + value = module.label4.context +} diff --git a/.terraform/modules/datadog-integration.this/examples/complete/label5.tf b/.terraform/modules/datadog-integration.this/examples/complete/label5.tf new file mode 100755 index 0000000..0f0a76e --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/complete/label5.tf @@ -0,0 +1,33 @@ +module "label5" { + source = "../../" + enabled = false + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + } +} + +output "label5" { + value = { + id = module.label5.id + name = module.label5.name + namespace = module.label5.namespace + stage = module.label5.stage + attributes = module.label5.attributes + delimiter = module.label5.delimiter + } +} + +output "label5_tags" { + value = module.label5.tags +} + +output "label5_context" { + value = module.label5.context +} diff --git a/.terraform/modules/datadog-integration.this/examples/complete/label6f.tf b/.terraform/modules/datadog-integration.this/examples/complete/label6f.tf new file mode 100755 index 0000000..1ce1bab --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/complete/label6f.tf @@ -0,0 +1,20 @@ +module "label6f" { + source = "../../" + + delimiter = "~" + id_length_limit = 0 + + # Use values from tfvars + context = module.this.context +} + +output "label6f" { + value = { + id = module.label6f.id + id_full = module.label6f.id_full + } +} + +output "label6f_tags" { + value = module.label6f.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.this/examples/complete/label6t.tf b/.terraform/modules/datadog-integration.this/examples/complete/label6t.tf new file mode 100755 index 0000000..b5d9bc1 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/complete/label6t.tf @@ -0,0 +1,19 @@ +module "label6t" { + source = "../../" + + # Use values from tfvars, + # specifically: complete.auto.tfvars + context = module.this.context +} + +output "label6t" { + value = { + id = module.label6t.id + id_full = module.label6t.id_full + id_length_limit = module.this.context.id_length_limit + } +} + +output "label6t_tags" { + value = module.label6t.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog-integration.this/examples/complete/label7.tf b/.terraform/modules/datadog-integration.this/examples/complete/label7.tf new file mode 100755 index 0000000..bb365d4 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/complete/label7.tf @@ -0,0 +1,44 @@ +module "label7a" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + } +} + +module "label7" { + source = "../../" + + attributes = ["nodegroup"] + + context = module.label7a.context +} + + +output "label7" { + value = { + id = module.label7.id + name = module.label7.name + namespace = module.label7.namespace + stage = module.label7.stage + attributes = module.label7.attributes + delimiter = module.label7.delimiter + } +} + +output "label7_id" { + value = module.label7.id +} + +output "label7_attributes" { + value = module.label7.attributes +} + +output "label7_context" { + value = module.label7.context +} diff --git a/.terraform/modules/datadog-integration.this/examples/complete/label8d.tf b/.terraform/modules/datadog-integration.this/examples/complete/label8d.tf new file mode 100755 index 0000000..4252419 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/complete/label8d.tf @@ -0,0 +1,44 @@ +module "label8d" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8d_context" { + source = "../../" + + context = module.label8d.context +} + +output "label8d_context_id" { + value = module.label8d_context.id +} + +output "label8d_context_context" { + value = module.label8d_context.context +} + +output "label8d_context_tags" { + value = module.label8d_context.tags +} + +output "label8d_id" { + value = module.label8d.id +} + +output "label8d_context" { + value = module.label8d.context +} + +output "label8d_tags" { + value = module.label8d.tags +} diff --git a/.terraform/modules/datadog-integration.this/examples/complete/label8dcd.tf b/.terraform/modules/datadog-integration.this/examples/complete/label8dcd.tf new file mode 100755 index 0000000..ccdae21 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/complete/label8dcd.tf @@ -0,0 +1,24 @@ +module "label8dcd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "x" +} + +module "label8dcd_context" { + source = "../../" + + context = module.label8dcd.context +} + +output "label8dcd_context_id" { + value = module.label8dcd_context.id +} + +output "label8dcd_id" { + value = module.label8dcd.id +} diff --git a/.terraform/modules/datadog-integration.this/examples/complete/label8dnd.tf b/.terraform/modules/datadog-integration.this/examples/complete/label8dnd.tf new file mode 100755 index 0000000..2edb378 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/complete/label8dnd.tf @@ -0,0 +1,24 @@ +module "label8dnd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "" +} + +module "label8dnd_context" { + source = "../../" + + context = module.label8dnd.context +} + +output "label8dnd_context_id" { + value = module.label8dnd_context.id +} + +output "label8dnd_id" { + value = module.label8dnd.id +} diff --git a/.terraform/modules/datadog-integration.this/examples/complete/label8l.tf b/.terraform/modules/datadog-integration.this/examples/complete/label8l.tf new file mode 100755 index 0000000..7462f9e --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/complete/label8l.tf @@ -0,0 +1,46 @@ +module "label8l" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "lower" + label_value_case = "lower" + + tags = { + "kubernetes.io/cluster/" = "shared" + "upperTEST" = "testUPPER" + } +} + +module "label8l_context" { + source = "../../" + + context = module.label8l.context +} + +output "label8l_context_id" { + value = module.label8l_context.id +} + +output "label8l_context_context" { + value = module.label8l_context.context +} + +output "label8l_context_tags" { + value = module.label8l_context.tags +} + +output "label8l_id" { + value = module.label8l.id +} + +output "label8l_context" { + value = module.label8l.context +} + +output "label8l_tags" { + value = module.label8l.tags +} diff --git a/.terraform/modules/datadog-integration.this/examples/complete/label8n.tf b/.terraform/modules/datadog-integration.this/examples/complete/label8n.tf new file mode 100755 index 0000000..fd4ad57 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/complete/label8n.tf @@ -0,0 +1,45 @@ +module "label8n" { + source = "../../" + + enabled = true + namespace = "EG" + environment = "demo" + name = "blue" + attributes = ["eks", "ClusteR"] + delimiter = "-" + label_value_case = "none" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8n_context" { + source = "../../" + + context = module.label8n.context +} + +output "label8n_context_id" { + value = module.label8n_context.id +} + +output "label8n_context_context" { + value = module.label8n_context.context +} + +output "label8n_context_tags" { + value = module.label8n_context.tags +} + +output "label8n_id" { + value = module.label8n.id +} + +output "label8n_context" { + value = module.label8n.context +} + +output "label8n_tags" { + value = module.label8n.tags +} diff --git a/.terraform/modules/datadog-integration.this/examples/complete/label8t.tf b/.terraform/modules/datadog-integration.this/examples/complete/label8t.tf new file mode 100755 index 0000000..cb54c7a --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/complete/label8t.tf @@ -0,0 +1,45 @@ +module "label8t" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["EKS", "cluster"] + delimiter = "-" + label_key_case = "title" + label_value_case = "title" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8t_context" { + source = "../../" + + context = module.label8t.context +} + +output "label8t_context_id" { + value = module.label8t_context.id +} + +output "label8t_context_context" { + value = module.label8t_context.context +} + +output "label8t_context_tags" { + value = module.label8t_context.tags +} + +output "label8t_id" { + value = module.label8t.id +} + +output "label8t_context" { + value = module.label8t.context +} + +output "label8t_tags" { + value = module.label8t.tags +} diff --git a/.terraform/modules/datadog-integration.this/examples/complete/label8u.tf b/.terraform/modules/datadog-integration.this/examples/complete/label8u.tf new file mode 100755 index 0000000..499535b --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/complete/label8u.tf @@ -0,0 +1,50 @@ +module "label8u" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "upper" + label_value_case = "upper" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8u_context" { + source = "../../" + + context = module.label8u.context +} + +output "label8u_context_id" { + value = module.label8u_context.id +} + +output "label8u_context_context" { + value = module.label8u_context.context +} + +// debug +output "label8u_context_normalized_context" { + value = module.label8u_context.normalized_context +} + +output "label8u_context_tags" { + value = module.label8u_context.tags +} + +output "label8u_id" { + value = module.label8u.id +} + +output "label8u_context" { + value = module.label8u.context +} + +output "label8u_tags" { + value = module.label8u.tags +} diff --git a/.terraform/modules/datadog-integration.this/examples/complete/versions.tf b/.terraform/modules/datadog-integration.this/examples/complete/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/examples/complete/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog-integration.this/exports/context.tf b/.terraform/modules/datadog-integration.this/exports/context.tf new file mode 100755 index 0000000..81f99b4 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/exports/context.tf @@ -0,0 +1,202 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog-integration.this/main.tf b/.terraform/modules/datadog-integration.this/main.tf new file mode 100755 index 0000000..0deda2b --- /dev/null +++ b/.terraform/modules/datadog-integration.this/main.tf @@ -0,0 +1,146 @@ +locals { + + defaults = { + label_order = ["namespace", "environment", "stage", "name", "attributes"] + regex_replace_chars = "/[^-a-zA-Z0-9]/" + delimiter = "-" + replacement = "" + id_length_limit = 0 + id_hash_length = 5 + label_key_case = "title" + label_value_case = "lower" + } + + # So far, we have decided not to allow overriding replacement or id_hash_length + replacement = local.defaults.replacement + id_hash_length = local.defaults.id_hash_length + + # The values provided by variables supersede the values inherited from the context object, + # except for tags and attributes which are merged. + input = { + # It would be nice to use coalesce here, but we cannot, because it + # is an error for all the arguments to coalesce to be empty. + enabled = var.enabled == null ? var.context.enabled : var.enabled + namespace = var.namespace == null ? var.context.namespace : var.namespace + environment = var.environment == null ? var.context.environment : var.environment + stage = var.stage == null ? var.context.stage : var.stage + name = var.name == null ? var.context.name : var.name + delimiter = var.delimiter == null ? var.context.delimiter : var.delimiter + # modules tack on attributes (passed by var) to the end of the list (passed by context) + attributes = compact(distinct(concat(coalesce(var.context.attributes, []), coalesce(var.attributes, [])))) + tags = merge(var.context.tags, var.tags) + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + label_order = var.label_order == null ? var.context.label_order : var.label_order + regex_replace_chars = var.regex_replace_chars == null ? var.context.regex_replace_chars : var.regex_replace_chars + id_length_limit = var.id_length_limit == null ? var.context.id_length_limit : var.id_length_limit + label_key_case = var.label_key_case == null ? lookup(var.context, "label_key_case", null) : var.label_key_case + label_value_case = var.label_value_case == null ? lookup(var.context, "label_value_case", null) : var.label_value_case + } + + + enabled = local.input.enabled + regex_replace_chars = coalesce(local.input.regex_replace_chars, local.defaults.regex_replace_chars) + + # string_label_names are names of inputs that are strings (not list of strings) used as labels + string_label_names = ["name", "namespace", "environment", "stage"] + normalized_labels = { for k in local.string_label_names : k => + local.input[k] == null ? "" : replace(local.input[k], local.regex_replace_chars, local.replacement) + } + normalized_attributes = compact(distinct([for v in local.input.attributes : replace(v, local.regex_replace_chars, local.replacement)])) + + formatted_labels = { for k in local.string_label_names : k => local.label_value_case == "none" ? local.normalized_labels[k] : + local.label_value_case == "title" ? title(lower(local.normalized_labels[k])) : + local.label_value_case == "upper" ? upper(local.normalized_labels[k]) : lower(local.normalized_labels[k]) + } + + attributes = compact(distinct([ + for v in local.normalized_attributes : (local.label_value_case == "none" ? v : + local.label_value_case == "title" ? title(lower(v)) : + local.label_value_case == "upper" ? upper(v) : lower(v)) + ])) + + name = local.formatted_labels["name"] + namespace = local.formatted_labels["namespace"] + environment = local.formatted_labels["environment"] + stage = local.formatted_labels["stage"] + + delimiter = local.input.delimiter == null ? local.defaults.delimiter : local.input.delimiter + label_order = local.input.label_order == null ? local.defaults.label_order : coalescelist(local.input.label_order, local.defaults.label_order) + id_length_limit = local.input.id_length_limit == null ? local.defaults.id_length_limit : local.input.id_length_limit + label_key_case = local.input.label_key_case == null ? local.defaults.label_key_case : local.input.label_key_case + label_value_case = local.input.label_value_case == null ? local.defaults.label_value_case : local.input.label_value_case + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + + tags = merge(local.generated_tags, local.input.tags) + + tags_as_list_of_maps = flatten([ + for key in keys(local.tags) : merge( + { + key = key + value = local.tags[key] + }, var.additional_tag_map) + ]) + + tags_context = { + # For AWS we need `Name` to be disambiguated since it has a special meaning + name = local.id + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = local.id_context.attributes + } + + generated_tags = { + for l in keys(local.tags_context) : + local.label_key_case == "upper" ? upper(l) : ( + local.label_key_case == "lower" ? lower(l) : title(lower(l)) + ) => local.tags_context[l] if length(local.tags_context[l]) > 0 + } + + id_context = { + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = join(local.delimiter, local.attributes) + } + + labels = [for l in local.label_order : local.id_context[l] if length(local.id_context[l]) > 0] + + id_full = join(local.delimiter, local.labels) + # Create a truncated ID if needed + delimiter_length = length(local.delimiter) + # Calculate length of normal part of ID, leaving room for delimiter and hash + id_truncated_length_limit = local.id_length_limit - (local.id_hash_length + local.delimiter_length) + # Truncate the ID and ensure a single (not double) trailing delimiter + id_truncated = local.id_truncated_length_limit <= 0 ? "" : "${trimsuffix(substr(local.id_full, 0, local.id_truncated_length_limit), local.delimiter)}${local.delimiter}" + # Support usages that disallow numeric characters. Would prefer tr 0-9 q-z but Terraform does not support it. + id_hash_plus = "${md5(local.id_full)}qrstuvwxyz" + id_hash_case = local.label_value_case == "title" ? title(local.id_hash_plus) : local.label_value_case == "upper" ? upper(local.id_hash_plus) : local.label_value_case == "lower" ? lower(local.id_hash_plus) : local.id_hash_plus + id_hash = replace(local.id_hash_case, local.regex_replace_chars, local.replacement) + # Create the short ID by adding a hash to the end of the truncated ID + id_short = substr("${local.id_truncated}${local.id_hash}", 0, local.id_length_limit) + id = local.id_length_limit != 0 && length(local.id_full) > local.id_length_limit ? local.id_short : local.id_full + + + # Context of this label to pass to other label modules + output_context = { + enabled = local.enabled + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + delimiter = local.delimiter + attributes = local.attributes + tags = local.tags + additional_tag_map = local.additional_tag_map + label_order = local.label_order + regex_replace_chars = local.regex_replace_chars + id_length_limit = local.id_length_limit + label_key_case = local.label_key_case + label_value_case = local.label_value_case + } + +} diff --git a/.terraform/modules/datadog-integration.this/outputs.tf b/.terraform/modules/datadog-integration.this/outputs.tf new file mode 100755 index 0000000..87ad1be --- /dev/null +++ b/.terraform/modules/datadog-integration.this/outputs.tf @@ -0,0 +1,88 @@ +output "id" { + value = local.enabled ? local.id : "" + description = "Disambiguated ID restricted to `id_length_limit` characters in total" +} + +output "id_full" { + value = local.enabled ? local.id_full : "" + description = "Disambiguated ID not restricted in length" +} + +output "enabled" { + value = local.enabled + description = "True if module is enabled, false otherwise" +} + +output "namespace" { + value = local.enabled ? local.namespace : "" + description = "Normalized namespace" +} + +output "environment" { + value = local.enabled ? local.environment : "" + description = "Normalized environment" +} + +output "name" { + value = local.enabled ? local.name : "" + description = "Normalized name" +} + +output "stage" { + value = local.enabled ? local.stage : "" + description = "Normalized stage" +} + +output "delimiter" { + value = local.enabled ? local.delimiter : "" + description = "Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes`" +} + +output "attributes" { + value = local.enabled ? local.attributes : [] + description = "List of attributes" +} + +output "tags" { + value = local.enabled ? local.tags : {} + description = "Normalized Tag map" +} + +output "additional_tag_map" { + value = local.additional_tag_map + description = "The merged additional_tag_map" +} + +output "label_order" { + value = local.label_order + description = "The naming order actually used to create the ID" +} + +output "regex_replace_chars" { + value = local.regex_replace_chars + description = "The regex_replace_chars actually used to create the ID" +} + +output "id_length_limit" { + value = local.id_length_limit + description = "The id_length_limit actually used to create the ID, with `0` meaning unlimited" +} + +output "tags_as_list_of_maps" { + value = local.tags_as_list_of_maps + description = "Additional tags as a list of maps, which can be used in several AWS resources" +} + +output "normalized_context" { + value = local.output_context + description = "Normalized context of this module" +} + +output "context" { + value = local.input + description = <<-EOT + Merged but otherwise unmodified input to this module, to be used as context input to other modules. + Note: this version will have null values as defaults, not the values actually used as defaults. +EOT +} + diff --git a/.terraform/modules/datadog-integration.this/test/Makefile b/.terraform/modules/datadog-integration.this/test/Makefile new file mode 100755 index 0000000..ea15d62 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/test/Makefile @@ -0,0 +1,43 @@ +TEST_HARNESS ?= https://github.com/cloudposse/test-harness.git +TEST_HARNESS_BRANCH ?= master +TEST_HARNESS_PATH = $(realpath .test-harness) +BATS_ARGS ?= --tap +BATS_LOG ?= test.log + +# Define a macro to run the tests +define RUN_TESTS +@echo "Running tests in $(1)" +@cd $(1) && bats $(BATS_ARGS) $(addsuffix .bats,$(addprefix $(TEST_HARNESS_PATH)/test/terraform/,$(TESTS))) +endef + +default: all + +-include Makefile.* + +## Provision the test-harnesss +.test-harness: + [ -d $@ ] || git clone --depth=1 -b $(TEST_HARNESS_BRANCH) $(TEST_HARNESS) $@ + +## Initialize the tests +init: .test-harness + +## Install all dependencies (OS specific) +deps:: + @exit 0 + +## Clean up the test harness +clean: + [ "$(TEST_HARNESS_PATH)" == "/" ] || rm -rf $(TEST_HARNESS_PATH) + +## Run all tests +all: module examples/complete + +## Run basic sanity checks against the module itself +module: export TESTS ?= installed lint get-modules module-pinning get-plugins provider-pinning validate terraform-docs input-descriptions output-descriptions +module: deps + $(call RUN_TESTS, ../) + +## Run tests against example +examples/complete: export TESTS ?= installed lint get-modules get-plugins validate init plan apply +examples/complete: deps + $(call RUN_TESTS, ../$@) diff --git a/.terraform/modules/datadog-integration.this/test/Makefile.alpine b/.terraform/modules/datadog-integration.this/test/Makefile.alpine new file mode 100755 index 0000000..7925b18 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/test/Makefile.alpine @@ -0,0 +1,5 @@ +ifneq (,$(wildcard /sbin/apk)) +## Install all dependencies for alpine +deps:: init + @apk add --update terraform-docs@cloudposse json2hcl@cloudposse +endif diff --git a/.terraform/modules/datadog-integration.this/test/src/Makefile b/.terraform/modules/datadog-integration.this/test/src/Makefile new file mode 100755 index 0000000..b772822 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/test/src/Makefile @@ -0,0 +1,30 @@ +export TF_CLI_ARGS_init ?= -get-plugins=true +export TERRAFORM_VERSION ?= $(shell curl -s https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r -M '.current_version' | cut -d. -f1-2) + +.DEFAULT_GOAL : all +.PHONY: all + +## Default target +all: test + +.PHONY : init +## Initialize tests +init: + @exit 0 + +.PHONY : test +## Run tests +test: init + go mod download + go test -v -timeout 60m -run TestExamplesComplete + +## Run tests in docker container +docker/test: + docker run --name terratest --rm -it -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e GITHUB_TOKEN \ + -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" \ + -v $(CURDIR)/../../:/module/ cloudposse/test-harness:latest -C /module/test/src test + +.PHONY : clean +## Clean up files +clean: + rm -rf ../../examples/complete/*.tfstate* diff --git a/.terraform/modules/datadog-integration.this/test/src/examples_complete_test.go b/.terraform/modules/datadog-integration.this/test/src/examples_complete_test.go new file mode 100755 index 0000000..156e293 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/test/src/examples_complete_test.go @@ -0,0 +1,293 @@ +package test + +import ( + "fmt" + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" + "github.com/qdm12/reprint" + "github.com/stretchr/testify/assert" +) + +type NLContext struct { + AdditionalTagMap map[string]string `json:"additional_tag_map"` + Attributes []string `json:"attributes"` + Delimiter interface{} `json:"delimiter"` + Enabled bool `json:"enabled"` + Environment interface{} `json:"environment"` + LabelOrder []string `json:"label_order"` + Name interface{} `json:"name"` + Namespace interface{} `json:"namespace"` + RegexReplaceChars interface{} `json:"regex_replace_chars"` + Stage interface{} `json:"stage"` + Tags map[string]string `json:"tags"` +} + +// Test the Terraform module in examples/complete using Terratest. +func TestExamplesComplete(t *testing.T) { + t.Parallel() + + terraformOptions := &terraform.Options{ + // The path to where our Terraform code is located + TerraformDir: "../../examples/complete", + Upgrade: true, + } + + // At the end of the test, run `terraform destroy` to clean up any resources that were created + defer terraform.Destroy(t, terraformOptions) + + // This will run `terraform init` and `terraform apply` and fail the test if there are any errors + terraform.InitAndApply(t, terraformOptions) + + expectedLabel1Context := NLContext{ + Enabled: true, + Namespace: "CloudPosse", + Environment: "UAT", + Stage: "build", + Name: "Winston Churchroom", + Attributes: []string{"fire", "water", "earth", "air"}, + Delimiter: "-", + LabelOrder: []string{"name", "environment", "stage", "attributes"}, + Tags: map[string]string{ + "City": "Dublin", + "Environment": "Private", + }, + AdditionalTagMap: map[string]string{}, + } + + var expectedLabel1NormalizedContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel1NormalizedContext) + expectedLabel1NormalizedContext.Namespace = "cloudposse" + expectedLabel1NormalizedContext.Environment = "uat" + expectedLabel1NormalizedContext.Name = "winstonchurchroom" + expectedLabel1NormalizedContext.RegexReplaceChars = "/[^-a-zA-Z0-9]/" + expectedLabel1NormalizedContext.Tags = map[string]string{ + "City": "Dublin", + "Environment": "Private", + "Namespace": "cloudposse", + "Stage": "build", + "Name": "winstonchurchroom-uat-build-fire-water-earth-air", + "Attributes": "fire-water-earth-air", + } + + var label1NormalizedContext, label1Context NLContext + // Run `terraform output` to get the value of an output variable + label1 := terraform.OutputMap(t, terraformOptions, "label1") + label1Tags := terraform.OutputMap(t, terraformOptions, "label1_tags") + terraform.OutputStruct(t, terraformOptions, "label1_normalized_context", &label1NormalizedContext) + terraform.OutputStruct(t, terraformOptions, "label1_context", &label1Context) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1["id"]) + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1Tags["Name"]) + assert.Equal(t, "Dublin", label1Tags["City"]) + assert.Equal(t, "Private", label1Tags["Environment"]) + assert.Equal(t, expectedLabel1NormalizedContext, label1NormalizedContext) + assert.Equal(t, expectedLabel1Context, label1Context) + + label1t1 := terraform.OutputMap(t, terraformOptions, "label1t1") + label1t1Tags := terraform.OutputMap(t, terraformOptions, "label1t1_tags") + assert.Equal(t, "winstonchurchroom-uat-6a0b34", label1t1["id"], + "Extra hash character should be added when trailing delimiter is removed") + assert.Equal(t, label1["id"], label1t1["id_full"], "id_full should not be truncated") + assert.Equal(t, label1t1["id"], label1t1Tags["Name"], "Name tag should match ID") + + label1t2 := terraform.OutputMap(t, terraformOptions, "label1t2") + label1t2Tags := terraform.OutputMap(t, terraformOptions, "label1t2_tags") + assert.Equal(t, "winstonchurchroom-uat-b-6a0b3", label1t2["id"]) + assert.Equal(t, label1t2["id"], label1t2Tags["Name"], "Name tag should match ID") + + // Run `terraform output` to get the value of an output variable + label2 := terraform.OutputMap(t, terraformOptions, "label2") + label2Tags := terraform.OutputMap(t, terraformOptions, "label2_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2["id"]) + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2Tags["Name"]) + assert.Equal(t, "London", label2Tags["City"]) + assert.Equal(t, "Public", label2Tags["Environment"]) + + var expectedLabel3cContext, label3cContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel3cContext) + expectedLabel3cContext.Name = "Starfish" + expectedLabel3cContext.Stage = "release" + expectedLabel3cContext.Delimiter = "." + expectedLabel3cContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3cContext.Tags["Eat"] = "Carrot" + expectedLabel3cContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3c := terraform.OutputMap(t, terraformOptions, "label3c") + label3cTags := terraform.OutputMap(t, terraformOptions, "label3c_tags") + terraform.OutputStruct(t, terraformOptions, "label3c_context", &label3cContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3c["id"]) + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3cTags["Name"]) + assert.Equal(t, expectedLabel3cContext, label3cContext) + + var expectedLabel3nContext, label3nContext NLContext + _ = reprint.FromTo(&expectedLabel1NormalizedContext, &expectedLabel3nContext) + expectedLabel3nContext.Name = "Starfish" + expectedLabel3nContext.Stage = "release" + expectedLabel3nContext.Delimiter = "." + expectedLabel3nContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3nContext.Tags["Eat"] = "Carrot" + expectedLabel3nContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3n := terraform.OutputMap(t, terraformOptions, "label3n") + label3nTags := terraform.OutputMap(t, terraformOptions, "label3n_tags") + terraform.OutputStruct(t, terraformOptions, "label3n_context", &label3nContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3n["id"]) + assert.Equal(t, label1Tags["Name"], label3nTags["Name"], + "Tag from label1 normalized context should overwrite label3n generated tag") + assert.Equal(t, expectedLabel3nContext, label3nContext) + + // Run `terraform output` to get the value of an output variable + label4 := terraform.OutputMap(t, terraformOptions, "label4") + label4Tags := terraform.OutputMap(t, terraformOptions, "label4_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4["id"]) + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4Tags["Name"]) + + // Run `terraform output` to get the value of an output variable + label5 := terraform.OutputMap(t, terraformOptions, "label5") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "", label5["id"]) + + label6f := terraform.OutputMap(t, terraformOptions, "label6f") + label6fTags := terraform.OutputMap(t, terraformOptions, "label6f_tags") + // Test of setting var.label_key_case = "lower", var.label_value_case = "upper" + assert.Equal(t, "CP~UW2~PRD~NULL-LABEL", label6f["id_full"]) + assert.Equal(t, label6f["id_full"], label6f["id"], "id should not be truncated") + assert.Equal(t, label6f["id"], label6fTags["name"], "Name tag should match ID") + + label6t := terraform.OutputMap(t, terraformOptions, "label6t") + label6tTags := terraform.OutputMap(t, terraformOptions, "label6t_tags") + assert.Equal(t, "CPUW2PRDNULL-LABEL", label6t["id_full"]) + assert.NotEqual(t, label6t["id_full"], label6t["id"], "id should be truncated") + assert.Equal(t, label6t["id"], label6tTags["name"], "Name tag should match ID") + assert.Equal(t, label6t["id_length_limit"], fmt.Sprintf("%d", len(label6t["id"])), + "Truncated ID length should equal length limit") + + label7 := terraform.OutputMap(t, terraformOptions, "label7") + assert.Equal(t, "eg-demo-blue-cluster-nodegroup", label7["id"], "var.attributes should be appended after context.attributes") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter=""` returns expected value of id, context id + label8dndID := terraform.Output(t, terraformOptions, "label8dnd_id") + label8dndContextID := terraform.Output(t, terraformOptions, "label8dnd_context_id") + assert.Equal(t, "egdemobluecluster", label8dndID) + assert.Equal(t, label8dndID, label8dndContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter="x"` returns expected value of id, context id + label8dcdID := terraform.Output(t, terraformOptions, "label8dcd_id") + label8dcdContextID := terraform.Output(t, terraformOptions, "label8dcd_context_id") + assert.Equal(t, "egxdemoxbluexcluster", label8dcdID) + assert.Equal(t, label8dcdID, label8dcdContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=lower` returns expected values of id, tags, context tags + label8dExpectedTags := map[string]string{ + "Attributes": "cluster", + "Environment": "demo", + "Name": "eg-demo-blue-cluster", + "Namespace": "eg", + "kubernetes.io/cluster/": "shared", + } + + label8dID := terraform.Output(t, terraformOptions, "label8d_id") + label8dContextID := terraform.Output(t, terraformOptions, "label8d_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8dID) + assert.Equal(t, label8dID, label8dContextID, "ID and context ID should be equal") + + label8dTags := terraform.OutputMap(t, terraformOptions, "label8d_tags") + label8dContextTags := terraform.OutputMap(t, terraformOptions, "label8d_context_tags") + + assert.Exactly(t, label8dExpectedTags, label8dTags, "generated tags are different from expected") + assert.Exactly(t, label8dTags, label8dContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=lower` and `label_value_case=lower` returns expected values of id, tags, context tags + label8lExpectedTags := map[string]string{ + "attributes": "cluster", + "environment": "demo", + "name": "eg-demo-blue-cluster", + "namespace": "eg", + "kubernetes.io/cluster/": "shared", + "upperTEST": "testUPPER", + } + + label8lID := terraform.Output(t, terraformOptions, "label8l_id") + label8lContextID := terraform.Output(t, terraformOptions, "label8l_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8lID) + assert.Equal(t, label8lID, label8lContextID, "ID and context ID should be equal") + + label8lTags := terraform.OutputMap(t, terraformOptions, "label8l_tags") + label8lContextTags := terraform.OutputMap(t, terraformOptions, "label8l_context_tags") + + assert.Exactly(t, label8lExpectedTags, label8lTags, "generated tags are different from expected") + assert.Exactly(t, label8lTags, label8lContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=title` returns expected values of id, tags, context tags + label8tExpectedTags := map[string]string{ + "Attributes": "Eks-Cluster", + "Environment": "Demo", + "Name": "Eg-Demo-Blue-Eks-Cluster", + "Namespace": "Eg", + "kubernetes.io/cluster/": "shared", + } + + label8tID := terraform.Output(t, terraformOptions, "label8t_id") + label8tContextID := terraform.Output(t, terraformOptions, "label8t_context_id") + assert.Equal(t, "Eg-Demo-Blue-Eks-Cluster", label8tID) + assert.Equal(t, label8tID, label8tContextID, "ID and context ID should be equal") + + label8tTags := terraform.OutputMap(t, terraformOptions, "label8t_tags") + label8tContextTags := terraform.OutputMap(t, terraformOptions, "label8t_context_tags") + + assert.Exactly(t, label8tExpectedTags, label8tTags, "generated tags are different from expected") + assert.Exactly(t, label8tTags, label8tContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=upper` and `label_value_case=upper` returns expected values of id, tags, context tags + label8uExpectedTags := map[string]string{ + "ATTRIBUTES": "CLUSTER", + "ENVIRONMENT": "DEMO", + "NAME": "EG-DEMO-BLUE-CLUSTER", + "NAMESPACE": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8uID := terraform.Output(t, terraformOptions, "label8u_id") + label8uContextID := terraform.Output(t, terraformOptions, "label8u_context_id") + assert.Equal(t, "EG-DEMO-BLUE-CLUSTER", label8uID) + assert.Equal(t, label8uID, label8uContextID, "ID and context ID should be equal") + + label8uTags := terraform.OutputMap(t, terraformOptions, "label8u_tags") + label8uContextTags := terraform.OutputMap(t, terraformOptions, "label8u_context_tags") + + assert.Exactly(t, label8uExpectedTags, label8uTags, "generated tags are different from expected") + assert.Exactly(t, label8uTags, label8uContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=none` returns expected values of id, tags, context tags + label8nExpectedTags := map[string]string{ + "Attributes": "eks-ClusteR", + "Environment": "demo", + "Name": "EG-demo-blue-eks-ClusteR", + "Namespace": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8nID := terraform.Output(t, terraformOptions, "label8n_id") + label8nContextID := terraform.Output(t, terraformOptions, "label8n_context_id") + assert.Equal(t, "EG-demo-blue-eks-ClusteR", label8nID) + assert.Equal(t, label8nID, label8nContextID, "ID and context ID should be equal") + + label8nTags := terraform.OutputMap(t, terraformOptions, "label8n_tags") + label8nContextTags := terraform.OutputMap(t, terraformOptions, "label8n_context_tags") + + assert.Exactly(t, label8nExpectedTags, label8nTags, "generated tags are different from expected") + assert.Exactly(t, label8nTags, label8nContextTags, "tags and context tags should be equal") +} diff --git a/.terraform/modules/datadog-integration.this/test/src/go.mod b/.terraform/modules/datadog-integration.this/test/src/go.mod new file mode 100755 index 0000000..d866541 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/test/src/go.mod @@ -0,0 +1,9 @@ +module github.com/cloudposse/terraform-null-label + +go 1.14 + +require ( + github.com/gruntwork-io/terratest v0.31.1 + github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 + github.com/stretchr/testify v1.6.1 +) diff --git a/.terraform/modules/datadog-integration.this/test/src/go.sum b/.terraform/modules/datadog-integration.this/test/src/go.sum new file mode 100755 index 0000000..b8d46b1 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/test/src/go.sum @@ -0,0 +1,595 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= +github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.5/go.mod h1:foo3aIXRQ90zFve3r0QiDsrjGDUwWhKl0ZOQy1CT14k= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= +github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200109221225-a4f60165b7a3/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= +github.com/gruntwork-io/terratest v0.31.1 h1:MPGe/5pGgJAIZ/hb+0LM1KyJKSi/QyxSkHoP9/CBhJg= +github.com/gruntwork-io/terratest v0.31.1/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= +github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4= +github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= +github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= +k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= +k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= +k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= +k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= +k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= +k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= +k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= +modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/.terraform/modules/datadog-integration.this/variables.tf b/.terraform/modules/datadog-integration.this/variables.tf new file mode 100755 index 0000000..40fb268 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/variables.tf @@ -0,0 +1,157 @@ +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} diff --git a/.terraform/modules/datadog-integration.this/versions.tf b/.terraform/modules/datadog-integration.this/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog-integration.this/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog-message-alerting b/.terraform/modules/datadog-message-alerting new file mode 160000 index 0000000..518c7ed --- /dev/null +++ b/.terraform/modules/datadog-message-alerting @@ -0,0 +1 @@ +Subproject commit 518c7ed71b17184fe82bda5b02543def5e37b747 diff --git a/.terraform/modules/datadog-message-alerting-bh-only/CHANGELOG.md b/.terraform/modules/datadog-message-alerting-bh-only/CHANGELOG.md new file mode 100755 index 0000000..c582413 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/CHANGELOG.md @@ -0,0 +1,472 @@ +# v4+ + +See [Github releases](https://github.com/claranet/terraform-datadog-monitors/releases) for versions `>= v4.0.0`. + +# v3.6.0 (January 27, 2021) + +## Improvement + +* Add monitor for Google Cloud Platform Memorystore Redis system memory usage ratio +* [[MN-587](https://onejira.atlassian.net/browse/MN-587)] - MN-587 Add ProxySQL monitors + +# v3.5.0 (August 27, 2020) + +## Bug + +* [[MN-581](https://onejira.atlassian.net/browse/MN-581)] - repair CI now pt-monitoring is dead + +## Improvement + +* [[MN-580](https://onejira.atlassian.net/browse/MN-580)] - Terraform 0.13 compatibility for datadog modules + +# v3.4.0 (March 30, 2020) + +## Bug + +* [[MN-574](https://onejira.atlassian.net/browse/MN-574)] - Fix k8s pod phases status + +## Improvement + +* [[MN-563](https://onejira.atlassian.net/browse/MN-563)] - TFenv support +* [[MN-571](https://onejira.atlassian.net/browse/MN-571)] - Azure AppGateway change metric + +## New Feature + +* [[MN-221](https://onejira.atlassian.net/browse/MN-221)] - Monitors for Zookeeper +* [[MN-496](https://onejira.atlassian.net/browse/MN-496)] - Customize the group by on the monitors + +# v3.3.0 (January 23, 2020) + +## Bug + +* [[MN-556](https://onejira.atlassian.net/browse/MN-556)] - Some monitors doesn't have customizable no_data_timeframe +* [[MN-558](https://onejira.atlassian.net/browse/MN-558)] - AZure Application gateway monitoring healthy host check has no data +* [[MN-562](https://onejira.atlassian.net/browse/MN-562)] - Fix perpetual diff on no_data_timeframe + +## Improvement + +* [[MN-527](https://onejira.atlassian.net/browse/MN-527)] - Disable memory forecast monitor for gcp cloudsql +* [[MN-547](https://onejira.atlassian.net/browse/MN-547)] - Add monitor for MySQL lag and replication +* [[MN-559](https://onejira.atlassian.net/browse/MN-559)] - Remove awk hack and use terraform-docs 0.8.0 +* [[MN-561](https://onejira.atlassian.net/browse/MN-561)] - Add targetgroup in group by for ALB monitors + +## New Feature + +* [[MN-521](https://onejira.atlassian.net/browse/MN-521)] - Monitors for AWS ECS Fargate +* [[MN-554](https://onejira.atlassian.net/browse/MN-554)] - Monitors for K8S Velero +* [[MN-557](https://onejira.atlassian.net/browse/MN-557)] - SQL Server monitors +* [[MN-560](https://onejira.atlassian.net/browse/MN-560)] - Monitors for solr + +# v3.2.0 (December 13, 2019) + +## Bug + +* [[MN-512](https://onejira.atlassian.net/browse/MN-512)] - Elasticsearch latency is a counter +* [[MN-516](https://onejira.atlassian.net/browse/MN-516)] - ELB & ALB "no healthy instances" monitor's value is not accurate +* [[MN-518](https://onejira.atlassian.net/browse/MN-518)] - Respect best practice for message mention +* [[MN-523](https://onejira.atlassian.net/browse/MN-523)] - Fix Azure server farm status aggregator +* [[MN-524](https://onejira.atlassian.net/browse/MN-524)] - Azure virtual machine free space monitor has no data +* [[MN-526](https://onejira.atlassian.net/browse/MN-526)] - Fix wrong percentage calculation on GCP pubsub messages unavailable +* [[MN-530](https://onejira.atlassian.net/browse/MN-530)] - Fix RDS Replica Lag monitors name (use ms instead of %) +* [[MN-532](https://onejira.atlassian.net/browse/MN-532)] - Syntax warning on ignore_changes attribute +* [[MN-535](https://onejira.atlassian.net/browse/MN-535)] - Fix HCL2 syntax +* [[MN-544](https://onejira.atlassian.net/browse/MN-544)] - kubernetescluster tag does not exist anymore + +## Documentation + +* [[MN-519](https://onejira.atlassian.net/browse/MN-519)] - Opensource integrations and monitors + +## Epic + +* [[MN-62](https://onejira.atlassian.net/browse/MN-62)] - Monitors for AWS ECS + +## Improvement + +* [[MN-364](https://onejira.atlassian.net/browse/MN-364)] - Monitors for AWS NLB +* [[MN-509](https://onejira.atlassian.net/browse/MN-509)] - Fix monitor name for storage account monitor +* [[MN-510](https://onejira.atlassian.net/browse/MN-510)] - Fix metric for storage account queue monitor +* [[MN-513](https://onejira.atlassian.net/browse/MN-513)] - Fix false alarms on Azure storage monitoring +* [[MN-514](https://onejira.atlassian.net/browse/MN-514)] - Replace avg with min on ElasticSearch fetch latency +* [[MN-517](https://onejira.atlassian.net/browse/MN-517)] - Make warning threshold customizable on load balancer healthy instances monitors +* [[MN-531](https://onejira.atlassian.net/browse/MN-531)] - Add time aggregator on RDS Replica Lag Monitor +* [[MN-541](https://onejira.atlassian.net/browse/MN-541)] - Add notify_no_data parameter on every monitors where it is true +* [[MN-543](https://onejira.atlassian.net/browse/MN-543)] - alerting message could use common recovering conditional variable + +## New Feature + +* [[MN-182](https://onejira.atlassian.net/browse/MN-182)] - Monitors structure and config examples / stack template +* [[MN-366](https://onejira.atlassian.net/browse/MN-366)] - Monitors for Azure Application Gateway +* [[MN-525](https://onejira.atlassian.net/browse/MN-525)] - Monitors for AWS Beanstalk + +# v3.1.2 (September 09, 2019) + +## Improvement + +* [[MN-508](https://onejira.atlassian.net/browse/MN-508)] - GCP Pub/Sub Topic no data removal + +# v3.1.1 (September 06, 2019) + +## Improvement + +* [[MN-507](https://onejira.atlassian.net/browse/MN-507)] - add manifest for pubsub monitors + +# v3.1.0 (September 06, 2019) + +## Bug + +* [[MN-481](https://onejira.atlassian.net/browse/MN-481)] - Fix alb latency metric unit and homogenize latency thresholds + +## Documentation + +* [[MN-495](https://onejira.atlassian.net/browse/MN-495)] - Add requirements to kubernetes monitors readme + +## Improvement + +* [[MN-400](https://onejira.atlassian.net/browse/MN-400)] - GCP Pub Sub improvements +* [[MN-456](https://onejira.atlassian.net/browse/MN-456)] - remove as_count() on kubernetes_state.container.status_report.count.waiting +* [[MN-480](https://onejira.atlassian.net/browse/MN-480)] - Increase alert treshold for Stream Analytics streaming units utilization +* [[MN-482](https://onejira.atlassian.net/browse/MN-482)] - Ignore silenced since we now must use downtime instead +* [[MN-484](https://onejira.atlassian.net/browse/MN-484)] - Ajust monitor Hub Too many d2c telemetry ingress not sent +* [[MN-486](https://onejira.atlassian.net/browse/MN-486)] - Remove workaround for here doc fmt now it is fixed in terraform 0.12.6 +* [[MN-494](https://onejira.atlassian.net/browse/MN-494)] - Refactor auto update scripts +* [[MN-502](https://onejira.atlassian.net/browse/MN-502)] - Increase basic system triggers timeframes +* [[MN-504](https://onejira.atlassian.net/browse/MN-504)] - Update terraform and provider versions + +## New Feature + +* [[MN-39](https://onejira.atlassian.net/browse/MN-39)] - Monitors for Newrelic +* [[MN-413](https://onejira.atlassian.net/browse/MN-413)] - Terraform feature for pagerduty integration +* [[MN-455](https://onejira.atlassian.net/browse/MN-455)] - Monitor for kubernetes_state.container.status_report.count.terminated +* [[MN-46](https://onejira.atlassian.net/browse/MN-46)] - Monitors for AWS Lambdas +* [[MN-472](https://onejira.atlassian.net/browse/MN-472)] - Monitors for AWS SQS +* [[MN-485](https://onejira.atlassian.net/browse/MN-485)] - docker image for datadog terraform +* [[MN-487](https://onejira.atlassian.net/browse/MN-487)] - Datadog monitors VM integration RAM reserved +* [[MN-489](https://onejira.atlassian.net/browse/MN-489)] - Datadog monitors Azure VM Disk +* [[MN-490](https://onejira.atlassian.net/browse/MN-490)] - Changelog generation on git repos +* [[MN-492](https://onejira.atlassian.net/browse/MN-492)] - Indicate if a monitor is disabled by default on the README of each module +* [[MN-493](https://onejira.atlassian.net/browse/MN-493)] - Datadog monitors VM integration - requests failed +* [[MN-497](https://onejira.atlassian.net/browse/MN-497)] - Monitors for Docker +* [[MN-498](https://onejira.atlassian.net/browse/MN-498)] - Monitors for Kong +* [[MN-499](https://onejira.atlassian.net/browse/MN-499)] - Monitors HTTP, DNS and TLS + +# v3.0.0 (July 05, 2019) + +## Improvement + +* [[MN-476](https://onejira.atlassian.net/browse/MN-476)] - check and update sets with more than 1 notify no data +* [[MN-479](https://onejira.atlassian.net/browse/MN-479)] - Upgrade datadog terraform provider to v2 + +## Bug + +* [[MN-460](https://onejira.atlassian.net/browse/MN-460)] - Fix filter tags usage on keyvault and cosmos monitors +* [[MN-461](https://onejira.atlassian.net/browse/MN-461)] - Repair CI since it uses last 0.12 version image +* [[MN-477](https://onejira.atlassian.net/browse/MN-477)] - Fix wrong variable in query for kubernetes node inodes monitor +* [[MN-478](https://onejira.atlassian.net/browse/MN-478)] - Fix diff between CI and local env for sort command + +## Epic + +* [[MN-459](https://onejira.atlassian.net/browse/MN-459)] - Upgrade to terraform 0.12 (HCL 2.0) + +# v2.9.0 (May 09, 2019) + +## Improvement + +* [[MN-441](https://onejira.atlassian.net/browse/MN-441)] - support extra tags for custom filtering +* [[MN-446](https://onejira.atlassian.net/browse/MN-446)] - Monitor Azure SQL Elastic Pool + +## New Feature + +* [[MN-182](https://onejira.atlassian.net/browse/MN-182)] - Monitors structure and config examples / stack template +* [[MN-236](https://onejira.atlassian.net/browse/MN-236)] - Append optional custom field to name of monitor +* [[MN-453](https://onejira.atlassian.net/browse/MN-453)] - Monitors for kubernetes kubelet volume stats space and inodes + +## Bug + +* [[MN-442](https://onejira.atlassian.net/browse/MN-442)] - Do not notify nodata on node unschedulable monitor +* [[MN-444](https://onejira.atlassian.net/browse/MN-444)] - Kubernetes status_report count waiting should not trigger on containercreating +* [[MN-451](https://onejira.atlassian.net/browse/MN-451)] - Nodata alerts on Azure App Services downscale + +## Epic + +* [[MN-449](https://onejira.atlassian.net/browse/MN-449)] - Datadog global CI + +# v2.8.0 (April 23, 2019) + +## Improvement + +* [[MN-320](https://onejira.atlassian.net/browse/MN-320)] - Prefer greater operator logic +* [[MN-326](https://onejira.atlassian.net/browse/MN-326)] - use multi line query and EOQ everywhere +* [[MN-327](https://onejira.atlassian.net/browse/MN-327)] - Fix warning name for load balancer +* [[MN-328](https://onejira.atlassian.net/browse/MN-328)] - Improve mysql Innodb pool monitors +* [[MN-330](https://onejira.atlassian.net/browse/MN-330)] - Fix grouping and counter on azure monitors +* [[MN-331](https://onejira.atlassian.net/browse/MN-331)] - Improve mysql throughput monitor +* [[MN-429](https://onejira.atlassian.net/browse/MN-429)] - Update reference from cloudnative to pt-mon +* [[MN-437](https://onejira.atlassian.net/browse/MN-437)] - Update CI to use new gitlab runner + +## New Feature + +* [[MN-114](https://onejira.atlassian.net/browse/MN-114)] - Monitors for Kubernetes +* [[MN-390](https://onejira.atlassian.net/browse/MN-390)] - Monitors for Azure Functions + +## Bug + +* [[MN-360](https://onejira.atlassian.net/browse/MN-360)] - Feature enable/disable monitors creation does not work +* [[MN-415](https://onejira.atlassian.net/browse/MN-415)] - Remove Azure DBforMySQL Active connection query +* [[MN-430](https://onejira.atlassian.net/browse/MN-430)] - Use "instance" dimension on Azure App Service monitors metrics + +# v2.7.0 (April 05, 2019) + +## Improvement + +* [[MN-385](https://onejira.atlassian.net/browse/MN-385)] - Add Azure EventGrid Datadog monitors +* [[MN-417](https://onejira.atlassian.net/browse/MN-417)] - Monitors for Azure Virtual Machine +* [[MN-418](https://onejira.atlassian.net/browse/MN-418)] - Monitors for Azure Load Balancer + +## New Feature + +* [[MN-391](https://onejira.atlassian.net/browse/MN-391)] - Monitors for Azure Search +* [[MN-424](https://onejira.atlassian.net/browse/MN-424)] - Monitors for GCE instance + +## Bug + +* [[MN-405](https://onejira.atlassian.net/browse/MN-405)] - Fix Azure CosmosDb monitors due to metrics changes +* [[MN-425](https://onejira.atlassian.net/browse/MN-425)] - Fix App Services response time monitor + +# v2.6.0 (March 08, 2019) + +## Bug + +* [[MN-402](https://onejira.atlassian.net/browse/MN-402)] - Fix Azure DBforMySQL Active connection monitor +* [[MN-403](https://onejira.atlassian.net/browse/MN-403)] - Fix apache perpetual diff on apache connect monitor + +## Improvement + +* [[MN-392](https://onejira.atlassian.net/browse/MN-392)] - Update terraform-docs version in CI for DD monitors +* [[MN-397](https://onejira.atlassian.net/browse/MN-397)] - Exclude secretlist activity from Azure Key Vault latency monitor +* [[MN-404](https://onejira.atlassian.net/browse/MN-404)] - Make mysql Innodb buffer pool more tolerant + +# v2.5.1 (January 24, 2019) + +## Bug + +* [[MN-387](https://onejira.atlassian.net/browse/MN-387)] - Azure IotHub monitors triggers nodata alerts since 2.5.0 + +# v2.5.0 (January 23, 2019) + +## Bug + +* [[MN-335](https://onejira.atlassian.net/browse/MN-335)] - Fix successful monitors false alarms +* [[MN-383](https://onejira.atlassian.net/browse/MN-383)] - Remove Azure Monitors using compute_consumption_percent +* [[MN-386](https://onejira.atlassian.net/browse/MN-386)] - Caas Nginx Ingress monitor fix and update for VTS + +## Improvement + +* [[MN-237](https://onejira.atlassian.net/browse/MN-237)] - Add new Azure Monitors +* [[MN-295](https://onejira.atlassian.net/browse/MN-295)] - Remove Azure global feature +* [[MN-317](https://onejira.atlassian.net/browse/MN-317)] - Prefix all cloudprovider filter tag with +* [[MN-332](https://onejira.atlassian.net/browse/MN-332)] - Add filter_tags on IOTHub monitors +* [[MN-344](https://onejira.atlassian.net/browse/MN-344)] - add default to hit ratio monitors +* [[MN-377](https://onejira.atlassian.net/browse/MN-377)] - Monitor Azure SQL Server status with DD + +## New Feature + +* [[MN-336](https://onejira.atlassian.net/browse/MN-336)] - Convert bitbucket pipeline to gitlab ci + +# v2.4.0 (October 03, 2018) + +## Bug + +* [[MN-301](https://onejira.atlassian.net/browse/MN-301)] - Manage exclude on the module for filters +* [[MN-323](https://onejira.atlassian.net/browse/MN-323)] - fix pipeline using terraform-docs version 0.4.0 + +## Improvement + +* [[MN-309](https://onejira.atlassian.net/browse/MN-309)] - Improve monitors using as_count() and division + +## New Feature + +* [[MN-246](https://onejira.atlassian.net/browse/MN-246)] - Monitors for Azure MySQL +* [[MN-310](https://onejira.atlassian.net/browse/MN-310)] - Monitors for Azure Postgresql +* [[MN-316](https://onejira.atlassian.net/browse/MN-316)] - Monitors for Azure server farms + +# v2.3.1 (September 27, 2018) + +## Bug + +* [[MN-313](https://onejira.atlassian.net/browse/MN-313)] - elasticache memcached hit ratio miss multiplication by 100 + +## Improvement + +* [[MN-306](https://onejira.atlassian.net/browse/MN-306)] - Use system.load.norm.5 instead of system.load.5 +* [[MN-307](https://onejira.atlassian.net/browse/MN-307)] - GCP CloudSQL failover monitor increase timeframe +* [[MN-308](https://onejira.atlassian.net/browse/MN-308)] - Improve load balancer healthly host monitor +* [[MN-311](https://onejira.atlassian.net/browse/MN-311)] - Generate modules.tf with dynamic path +* [[MN-312](https://onejira.atlassian.net/browse/MN-312)] - Update readme with terraform-docs 0.4.0 +* [[MN-315](https://onejira.atlassian.net/browse/MN-315)] - Doc monitor / system / generic: free memory message + +# v2.3.0 (September 20, 2018) + +## Bug + +* [[MN-273](https://onejira.atlassian.net/browse/MN-273)] - service check query syntax does not work anymore +* [[MN-304](https://onejira.atlassian.net/browse/MN-304)] - Add default function to all latency based aws monitors + +## Improvement + +* [[MN-159](https://onejira.atlassian.net/browse/MN-159)] - Split delay variable in two separate variables (evaluation and new host) +* [[MN-162](https://onejira.atlassian.net/browse/MN-162)] - Add possibilty to disable / enable monitors +* [[MN-199](https://onejira.atlassian.net/browse/MN-199)] - Advanced monitors for Mongodb +* [[MN-275](https://onejira.atlassian.net/browse/MN-275)] - manage diff on monitor type from terraform +* [[MN-287](https://onejira.atlassian.net/browse/MN-287)] - Update service check monitors and doc +* [[MN-288](https://onejira.atlassian.net/browse/MN-288)] - Update all monitors with new tagging convention +* [[MN-293](https://onejira.atlassian.net/browse/MN-293)] - Optimize ci pipeline +* [[MN-294](https://onejira.atlassian.net/browse/MN-294)] - handle specific example for readme auto generation +* [[MN-300](https://onejira.atlassian.net/browse/MN-300)] - Improve and sandardize thresholds on GCP LB + +## New Feature + +* [[MN-32](https://onejira.atlassian.net/browse/MN-32)] - Monitors for AWS Elasticache +* [[MN-92](https://onejira.atlassian.net/browse/MN-92)] - Monitors for Mongodb +* [[MN-105](https://onejira.atlassian.net/browse/MN-105)] - Monitors for PostgreSQL +* [[MN-122](https://onejira.atlassian.net/browse/MN-122)] - Replication lag monitor for RDS +* [[MN-142](https://onejira.atlassian.net/browse/MN-142)] - Monitors for MySQL +* [[MN-224](https://onejira.atlassian.net/browse/MN-224)] - Monitors for GCP Cloud SQL +* [[MN-226](https://onejira.atlassian.net/browse/MN-226)] - Monitors for GCP PubSub +* [[MN-227](https://onejira.atlassian.net/browse/MN-227)] - Monitors for GCP LB +* [[MN-228](https://onejira.atlassian.net/browse/MN-228)] - Monitors for ElasticSearch +* [[MN-230](https://onejira.atlassian.net/browse/MN-230)] - Monitors for GCP BigQuery +* [[MN-247](https://onejira.atlassian.net/browse/MN-247)] - Monitors for Ark backups +* [[MN-248](https://onejira.atlassian.net/browse/MN-248)] - Monitors for Nginx Ingress Controller +* [[MN-271](https://onejira.atlassian.net/browse/MN-271)] - Monitors for Redis +* [[MN-281](https://onejira.atlassian.net/browse/MN-281)] - Monitor for disk forecast (system-generic) +* [[MN-284](https://onejira.atlassian.net/browse/MN-284)] - Add extra tags management to monitors +* [[MN-286](https://onejira.atlassian.net/browse/MN-286)] - Host Unreachable monitor on system generic +* [[MN-289](https://onejira.atlassian.net/browse/MN-289)] - Monitors for Nginx +* [[MN-290](https://onejira.atlassian.net/browse/MN-290)] - Monitors for Php-fpm + +# v2.2.1 (August 08, 2018) + +## Bug + +* [[MN-272](https://onejira.atlassian.net/browse/MN-272)] - php fpm has changed from port to ping_url for group by +* [[MN-276](https://onejira.atlassian.net/browse/MN-276)] - Fix ALB / ELB space aggregator + +# v2.2.0 (July 23, 2018) + +## Improvement + +* [[MN-259](https://onejira.atlassian.net/browse/MN-259)] - Improve readme generator + +## New Feature + +* [[MN-233](https://onejira.atlassian.net/browse/MN-233)] - Update main readme automatically +* [[MN-234](https://onejira.atlassian.net/browse/MN-234)] - Automatically generate output for each monitor + +# v2.1.1 (July 10, 2018) + +## Bug + +* [[MN-239](https://onejira.atlassian.net/browse/MN-239)] - Fix alb no healthy instances thresholds + +# v2.1.0 (June 29, 2018) + +## Bug + +* [[MN-168](https://onejira.atlassian.net/browse/MN-168)] - Apache can connect fails on query error + +## Improvement + +* [[MN-160](https://onejira.atlassian.net/browse/MN-160)] - Generalize the timeframe best practice +* [[MN-170](https://onejira.atlassian.net/browse/MN-170)] - Increase timeframe of ALB no healthy instances monitor +* [[MN-179](https://onejira.atlassian.net/browse/MN-179)] - No data events on Free disk inodes, Free disk space monitors +* [[MN-184](https://onejira.atlassian.net/browse/MN-184)] - no_data_timeframe should never be defined +* [[MN-185](https://onejira.atlassian.net/browse/MN-185)] - Monitors for Azure ServiceBus +* [[MN-197](https://onejira.atlassian.net/browse/MN-197)] - Ignore cache and buffer on memory monitor + +## New Feature + +* [[MN-191](https://onejira.atlassian.net/browse/MN-191)] - variabilize aggregator and timeframe when needed +* [[MN-231](https://onejira.atlassian.net/browse/MN-231)] - Update readme for every monitors sets easily + +## Documentation + +* [[MN-181](https://onejira.atlassian.net/browse/MN-181)] - update aws vpn readme to remove vpn_tunnel_address + +# v2.0.1 (April 02, 2018) + +## Bug + +* [[MN-166](https://onejira.atlassian.net/browse/MN-166)] - Fix apigateway latency notify on no data + +# v2.0.0 (March 25, 2018) + +## Bug + +* [[MN-81](https://onejira.atlassian.net/browse/MN-81)] - Fix basic monitors +* [[MN-88](https://onejira.atlassian.net/browse/MN-88)] - Treshold too high on aws_elb_latency +* [[MN-108](https://onejira.atlassian.net/browse/MN-108)] - typo monitor name apache middleware +* [[MN-113](https://onejira.atlassian.net/browse/MN-113)] - fix AWS ElasticSearch status monitor (aws.es.cluster_statusyellow) +* [[MN-121](https://onejira.atlassian.net/browse/MN-121)] - Fix ELB_backend_latency error +* [[MN-127](https://onejira.atlassian.net/browse/MN-127)] - Fix system tag in agent.yml +* [[MN-128](https://onejira.atlassian.net/browse/MN-128)] - [Datadog] Monitors for ELB issue with group by loadbalancer +* [[MN-139](https://onejira.atlassian.net/browse/MN-139)] - no data support for monitor name templating + +## Improvement + +* [[MN-66](https://onejira.atlassian.net/browse/MN-66)] - Refactor monitors repo with directories +* [[MN-96](https://onejira.atlassian.net/browse/MN-96)] - Update old monitors with new best practices +* [[MN-99](https://onejira.atlassian.net/browse/MN-99)] - Azure App Service monitor : count 2xx & 3xx http status codes as successful +* [[MN-102](https://onejira.atlassian.net/browse/MN-102)] - Auto-recovery for no-data tolerant monitors +* [[MN-124](https://onejira.atlassian.net/browse/MN-124)] - Add message input per monitor +* [[MN-134](https://onejira.atlassian.net/browse/MN-134)] - RAM alerts are now in non-business hours alerting by default. +* [[MN-135](https://onejira.atlassian.net/browse/MN-135)] - Use default on Event Hub query and update the used metrics +* [[MN-136](https://onejira.atlassian.net/browse/MN-136)] - Use rates for Azure IoT Hub monitors +* [[MN-137](https://onejira.atlassian.net/browse/MN-137)] - Use min as aggregate for Azure app services response time monitor +* [[MN-140](https://onejira.atlassian.net/browse/MN-140)] - Add a default function for api gateway, elb and alb monitors + +## New Feature + +* [[MN-48](https://onejira.atlassian.net/browse/MN-48)] - Monitors for API Gateway +* [[MN-49](https://onejira.atlassian.net/browse/MN-49)] - improve basic monitors +* [[MN-82](https://onejira.atlassian.net/browse/MN-82)] - Monitor message should be composed from variables +* [[MN-91](https://onejira.atlassian.net/browse/MN-91)] - Monitors for AWS VPN +* [[MN-107](https://onejira.atlassian.net/browse/MN-107)] - Monitors for AWS Elasticsearch Service +* [[MN-110](https://onejira.atlassian.net/browse/MN-110)] - Monitors for AWS Kinesis Firehose streams +* [[MN-112](https://onejira.atlassian.net/browse/MN-112)] - Monitors for AWS ALB + +## Sub-task + +* [[MN-30](https://onejira.atlassian.net/browse/MN-30)] - Monitors for AWS RDS +* [[MN-34](https://onejira.atlassian.net/browse/MN-34)] - Monitors for AWS ELB +* [[MN-74](https://onejira.atlassian.net/browse/MN-74)] - Azure App Services monitors +* [[MN-75](https://onejira.atlassian.net/browse/MN-75)] - Azure SQL monitors +* [[MN-76](https://onejira.atlassian.net/browse/MN-76)] - Azure Redis monitors +* [[MN-77](https://onejira.atlassian.net/browse/MN-77)] - Azure Event Hub monitors +* [[MN-78](https://onejira.atlassian.net/browse/MN-78)] - Azure Stream Analytics monitors +* [[MN-79](https://onejira.atlassian.net/browse/MN-79)] - Azure Storage monitors +* [[MN-80](https://onejira.atlassian.net/browse/MN-80)] - Azure IOT Hub monitors +* [[MN-90](https://onejira.atlassian.net/browse/MN-90)] - API Management monitors + +## Story + +* [[MN-73](https://onejira.atlassian.net/browse/MN-73)] - Azure managed services monitors + +## Documentation + +* [[MN-97](https://onejira.atlassian.net/browse/MN-97)] - Update readme on terraform monitors repo + +# v1.0.0 (December 24, 2017) + +## Improvement + +* [[MN-93](https://onejira.atlassian.net/browse/MN-93)] - AWS ELB custom tags +* [[MN-131](https://onejira.atlassian.net/browse/MN-131)] - Replace comparator variable by a hardcode comparator in monitor name +* [[MN-144](https://onejira.atlassian.net/browse/MN-144)] - Default nodata message must be 24x7 + +## New Feature + +* [[MN-43](https://onejira.atlassian.net/browse/MN-43)] - Agent installation + +## Story + +* [[MN-27](https://onejira.atlassian.net/browse/MN-27)] - Monitors for main middlewares diff --git a/.terraform/modules/datadog-message-alerting-bh-only/CONTRIBUTING.md b/.terraform/modules/datadog-message-alerting-bh-only/CONTRIBUTING.md new file mode 100755 index 0000000..8c1d90d --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/CONTRIBUTING.md @@ -0,0 +1,102 @@ +# Contributing + +When contributing to this repository, please first discuss the change you wish to make via issue, +email, or any other method with the owners of this repository before making a change. + +Please note we have a [code of conduct](#code-of-conduct), follow it in all your interactions with the project. + +## Considerations + +* If you have required permissions, you can create a branch from master else you can fork this repo to be able to submit a Pull Request. + +* [The changelog](CHANGELOG.md) is generated using issues IDs (Jira & Github) detected in commit messages which must follow `#GithubID My commit message` form. + +* If you would like to work on monitors you must follow our [templating best practices](TEMPLATING.md) to make this base homogenous and generic. + +* After any change, you will need to run the [auto update scripts](https://github.com/claranet/terraform-datadog-scripts/blob/master/README.md) to make sure all is up to date otherwise the CI pipeline will fail. + +## Pull Request Process + +1. Ensure to run the `auto_update.sh` script to be in an up to date and valid state. +2. Update the main README.md with details of changes to the interface, this includes new environment + variables, exposed ports, useful file locations and container parameters. +3. Increase the version numbers in any examples files and the README.md to the new version that this + Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). +4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you + do not have permission to do that, you may request the second reviewer to merge it for you. + +## Code of Conduct + +### Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +### Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +### Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +### Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +### Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at [FR-CloudPublic-github@fr.clara.net]. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +### Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/LICENSE b/.terraform/modules/datadog-message-alerting-bh-only/LICENSE new file mode 100755 index 0000000..6ad2829 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2018 Claranet + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/NOTICE b/.terraform/modules/datadog-message-alerting-bh-only/NOTICE new file mode 100755 index 0000000..3238949 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/NOTICE @@ -0,0 +1,13 @@ +Copyright (c) 2018-2019 Claranet + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/.terraform/modules/datadog-message-alerting-bh-only/README.md b/.terraform/modules/datadog-message-alerting-bh-only/README.md new file mode 100755 index 0000000..b5bbbc6 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/README.md @@ -0,0 +1,243 @@ +# DataDog Monitors +[![Changelog](https://img.shields.io/badge/changelog-release-green.svg)](CHANGELOG.md) [![Notice](https://img.shields.io/badge/notice-copyright-yellow.svg)](NOTICE) [![Apache V2 License](http://img.shields.io/badge/license-Apache%20V2-blue.svg)](LICENSE) [![ ](https://git.fr.clara.net/claranet/pt-monitoring/projects/datadog/terraform/monitors/badges/master/pipeline.svg)](https://git.fr.clara.net/claranet/pt-monitoring/projects/datadog/terraform/monitors/commits/master) + +This repository aims to provide a base of generic and pre configured monitors for [Datadog](https://www.datadoghq.com/) templated thanks to [Terraform](https://www.terraform.io/) and the [Datadog Provider](https://github.com/terraform-providers/terraform-provider-datadog). + +## Important notes + +* This repository provide multiple Terraform modules which could be imported, you must choose the one(s) you need. +* Each of these modules contains the most commons monitors, but they probably do not fulfill all your needs. +* You still can create some specific DataDog monitors after importing a module, it's even advisable to complete your needs. +* You will find a complete `README.md` on each module, explaining how to use it and its specificities if there. +* The `alerting-message` module could be used to easily generate a templating message to re-use and could be used multiple times to suit different use cases. +* Some monitors are disabled by default because not generic or "plug and play" enough, if you use them you will need to tweak them or in some cases disabled another one which could "duplicate" the check. + +## Getting started + +### Versions + +Here are the minimum versions required to use these modules of integrations. + +```hcl +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} + +``` + +_Note_: if you want to use Datadog provider v2, you need to use version 3 of the modules in this repository. + +### DataDog provider + +Here is the last tester terraform provider version for datadog but next versions should work too. + +``` +provider "datadog" { + api_key = var.datadog_api_key + app_key = var.datadog_app_key +} + +``` + +Both of the `datadog_api_key` and `datadog_app_key` are unique to the each datadog account. You can define them in `terraform.tfvars` file: + +``` +datadog_api_key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +datadog_app_key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +``` + +### Variables + +Some variables need to be declared. + +``` +variable "environment" { + type = string + default = "dev" +} + +variable "datadog_api_key" { + type = string +} + +variable "datadog_app_key" { + type = string +} + +``` + +### Modules declaration example + +A quick example of alerting message module declaration: + +``` +locals { + oncall_24x7 = "@pagerduty-MyPagerService_NBH" + oncall_office_hours = "@pagerduty-MyPagerService_BH" +} + +module "datadog-message-alerting" { + source = "claranet/monitors/datadog//common/alerting-message" + version = "{revision}" + + message_alert = local.oncall_24x7 + message_warning = local.oncall_office_hours + message_nodata = local.oncall_24x7 +} + +module "datadog-message-alerting-bh-only" { + source = "claranet/monitors/datadog//common/alerting-message" + version = "{revision}" + + message_alert = local.oncall_office_hours + message_warning = local.oncall_office_hours + message_nodata = local.oncall_office_hours +} + +module "datadog-monitors-system-generic" { + source = "claranet/monitors/datadog//system/generic" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message + + memory_message = module.datadog-message-alerting-bh-only.alerting-message + # Use variables to customize monitors configuration +} + +# Other monitors modules to declare ... +#module "datadog-monitors-my-monitors-set" { +# source = "claranet/monitors/datadog//my/monitors/set" +# version = "{revision}" +# +# environment = var.environment +# message = module.datadog-message-alerting.alerting-message +#} + +``` + +* Replace `{revision}` to the last git tag available on this repository. +* The `//` is very important, it's a terraform specific syntax used to separate git url and folder path. +* `my/monitors/set` represents the path to a monitors set sub directory listed below. + +## Contributions + +Contributions are always welcome. + +The easiest way is to fork the repository, duplicate a module as "template" and work on it. + +An internal CI will run the `auto_update.sh` script to compare with proposed changes and check if everything is up to date. + +So, when PR is ready you will need to run this script and push its changes to pass the CI, see [scripts repository](https://github.com/claranet/terraform-datadog-scripts/) for more information. + +For example, this will regenerate every READMEs thanks to [terraform-docs](https://github.com/segmentio/terraform-docs) currently in v0.9.1. + +## Monitors summary + +- [caas](https://github.com/claranet/terraform-datadog-monitors/tree/master/caas/) + - [docker](https://github.com/claranet/terraform-datadog-monitors/tree/master/caas/docker/) + - [kubernetes](https://github.com/claranet/terraform-datadog-monitors/tree/master/caas/kubernetes/) + - [ark](https://github.com/claranet/terraform-datadog-monitors/tree/master/caas/kubernetes/ark/) + - [cluster](https://github.com/claranet/terraform-datadog-monitors/tree/master/caas/kubernetes/cluster/) + - [ingress](https://github.com/claranet/terraform-datadog-monitors/tree/master/caas/kubernetes/ingress/) + - [vts](https://github.com/claranet/terraform-datadog-monitors/tree/master/caas/kubernetes/ingress/vts/) + - [node](https://github.com/claranet/terraform-datadog-monitors/tree/master/caas/kubernetes/node/) + - [pod](https://github.com/claranet/terraform-datadog-monitors/tree/master/caas/kubernetes/pod/) + - [velero](https://github.com/claranet/terraform-datadog-monitors/tree/master/caas/kubernetes/velero/) + - [workload](https://github.com/claranet/terraform-datadog-monitors/tree/master/caas/kubernetes/workload/) +- [cloud](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/) + - [aws](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/) + - [alb](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/alb/) + - [apigateway](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/apigateway/) + - [beanstalk](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/beanstalk/) + - [ecs](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/ecs/) + - [common](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/ecs/common/) + - [ec2-cluster](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/ecs/ec2-cluster/) + - [fargate](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/ecs/fargate/) + - [elasticache](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/elasticache/) + - [common](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/elasticache/common/) + - [memcached](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/elasticache/memcached/) + - [redis](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/elasticache/redis/) + - [elasticsearch](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/elasticsearch/) + - [elb](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/elb/) + - [kinesis-firehose](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/kinesis-firehose/) + - [lambda](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/lambda/) + - [nlb](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/nlb/) + - [rds](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/rds/) + - [aurora](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/rds/aurora/) + - [mysql](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/rds/aurora/mysql/) + - [postgresql](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/rds/aurora/postgresql/) + - [common](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/rds/common/) + - [sqs](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/sqs/) + - [vpn](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/vpn/) + - [azure](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/) + - [apimanagement](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/apimanagement/) + - [app-gateway](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/app-gateway/) + - [app-services](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/app-services/) + - [azure-search](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/azure-search/) + - [cosmosdb](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/cosmosdb/) + - [datalakestore](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/datalakestore/) + - [eventgrid](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/eventgrid/) + - [eventhub](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/eventhub/) + - [functions](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/functions/) + - [iothubs](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/iothubs/) + - [keyvault](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/keyvault/) + - [load-balancer](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/load-balancer/) + - [mysql](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/mysql/) + - [postgresql](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/postgresql/) + - [redis](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/redis/) + - [serverfarms](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/serverfarms/) + - [servicebus](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/servicebus/) + - [sql-database](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/sql-database/) + - [sql-elasticpool](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/sql-elasticpool/) + - [storage](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/storage/) + - [stream-analytics](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/stream-analytics/) + - [virtual-machine](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/virtual-machine/) + - [gcp](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/) + - [big-query](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/big-query/) + - [cloud-sql](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/cloud-sql/) + - [common](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/cloud-sql/common/) + - [mysql](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/cloud-sql/mysql/) + - [gce](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/gce/) + - [instance](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/gce/instance/) + - [lb](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/lb/) + - [memorystore](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/memorystore/) + - [redis](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/memorystore/redis/) + - [pubsub](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/pubsub/) + - [subscription](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/pubsub/subscription/) + - [topic](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/pubsub/topic/) +- [common](https://github.com/claranet/terraform-datadog-monitors/tree/master/common/) + - [alerting-message](https://github.com/claranet/terraform-datadog-monitors/tree/master/common/alerting-message/) + - [filter-tags](https://github.com/claranet/terraform-datadog-monitors/tree/master/common/filter-tags/) +- [database](https://github.com/claranet/terraform-datadog-monitors/tree/master/database/) + - [elasticsearch](https://github.com/claranet/terraform-datadog-monitors/tree/master/database/elasticsearch/) + - [mongodb](https://github.com/claranet/terraform-datadog-monitors/tree/master/database/mongodb/) + - [mysql](https://github.com/claranet/terraform-datadog-monitors/tree/master/database/mysql/) + - [postgresql](https://github.com/claranet/terraform-datadog-monitors/tree/master/database/postgresql/) + - [proxysql](https://github.com/claranet/terraform-datadog-monitors/tree/master/database/proxysql/) + - [redis](https://github.com/claranet/terraform-datadog-monitors/tree/master/database/redis/) + - [solr](https://github.com/claranet/terraform-datadog-monitors/tree/master/database/solr/) + - [sqlserver](https://github.com/claranet/terraform-datadog-monitors/tree/master/database/sqlserver/) + - [zookeeper](https://github.com/claranet/terraform-datadog-monitors/tree/master/database/zookeeper/) +- [middleware](https://github.com/claranet/terraform-datadog-monitors/tree/master/middleware/) + - [apache](https://github.com/claranet/terraform-datadog-monitors/tree/master/middleware/apache/) + - [kong](https://github.com/claranet/terraform-datadog-monitors/tree/master/middleware/kong/) + - [nginx](https://github.com/claranet/terraform-datadog-monitors/tree/master/middleware/nginx/) + - [php-fpm](https://github.com/claranet/terraform-datadog-monitors/tree/master/middleware/php-fpm/) +- [network](https://github.com/claranet/terraform-datadog-monitors/tree/master/network/) + - [dns](https://github.com/claranet/terraform-datadog-monitors/tree/master/network/dns/) + - [http](https://github.com/claranet/terraform-datadog-monitors/tree/master/network/http/) + - [ssl](https://github.com/claranet/terraform-datadog-monitors/tree/master/network/http/ssl/) + - [webcheck](https://github.com/claranet/terraform-datadog-monitors/tree/master/network/http/webcheck/) + - [tls](https://github.com/claranet/terraform-datadog-monitors/tree/master/network/tls/) +- [saas](https://github.com/claranet/terraform-datadog-monitors/tree/master/saas/) + - [new-relic](https://github.com/claranet/terraform-datadog-monitors/tree/master/saas/new-relic/) +- [system](https://github.com/claranet/terraform-datadog-monitors/tree/master/system/) + - [generic](https://github.com/claranet/terraform-datadog-monitors/tree/master/system/generic/) + - [unreachable](https://github.com/claranet/terraform-datadog-monitors/tree/master/system/unreachable/) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/TEMPLATING.md b/.terraform/modules/datadog-message-alerting-bh-only/TEMPLATING.md new file mode 100755 index 0000000..ce4138d --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/TEMPLATING.md @@ -0,0 +1,10 @@ +# Templating + +This documentation aims to help contributors to build their monitors: +* working with datadog and using some tips or advices. +* respect guideline to keep this base generic and usable for everybody. +* preserve homogeneity over every modules provided on this repository. + +## TODO + +To migrate from confluence diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/docker/README.md b/.terraform/modules/datadog-message-alerting-bh-only/caas/docker/README.md new file mode 100755 index 0000000..6916623 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/docker/README.md @@ -0,0 +1,83 @@ +# CAAS DOCKER DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-caas-docker" { + source = "claranet/monitors/datadog//caas/docker" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Docker Container Memory Used (disabled by default) +- Docker does not respond + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.memory_used](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.not_responding](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [memory\_used\_enabled](#input\_memory\_used\_enabled) | Flag to enable Container Memory Usage monitor | `string` | `"false"` | no | +| [memory\_used\_extra\_tags](#input\_memory\_used\_extra\_tags) | Extra tags for Container Memory Usage monitor | `list(string)` | `[]` | no | +| [memory\_used\_message](#input\_memory\_used\_message) | Custom message for the Container Memory Usage monitor | `string` | `""` | no | +| [memory\_used\_threshold\_critical](#input\_memory\_used\_threshold\_critical) | Container Memory Usage critical threshold | `string` | `90` | no | +| [memory\_used\_threshold\_warning](#input\_memory\_used\_threshold\_warning) | Container Memory Usage warning threshold | `string` | `85` | no | +| [memory\_used\_time\_aggregator](#input\_memory\_used\_time\_aggregator) | Time aggregator for the Container Memory Usage monitor | `string` | `"min"` | no | +| [memory\_used\_timeframe](#input\_memory\_used\_timeframe) | Timeframe for the Container Memory Usage monitor | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [not\_responding\_enabled](#input\_not\_responding\_enabled) | Flag to enable Docker does not respond monitor | `string` | `"true"` | no | +| [not\_responding\_extra\_tags](#input\_not\_responding\_extra\_tags) | Extra tags for Docker does not respond monitor | `list(string)` | `[]` | no | +| [not\_responding\_message](#input\_not\_responding\_message) | Custom message for Docker does not respond monitor | `string` | `""` | no | +| [not\_responding\_no\_data\_timeframe](#input\_not\_responding\_no\_data\_timeframe) | Docker does not respond monitor no data timeframe | `string` | `10` | no | +| [not\_responding\_threshold\_warning](#input\_not\_responding\_threshold\_warning) | Docker does not respond monitor (warning threshold) | `string` | `3` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [memory\_used\_id](#output\_memory\_used\_id) | id for monitor memory\_used | +| [not\_responding\_id](#output\_not\_responding\_id) | id for monitor not\_responding | +## Related documentation + +* [Datadog Docker integration](https://docs.datadoghq.com/integrations/docker_daemon/) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/docker/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/docker/inputs.tf new file mode 100755 index 0000000..9fdbb7e --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/docker/inputs.tf @@ -0,0 +1,123 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# +# Not Responding +# +variable "not_responding_enabled" { + description = "Flag to enable Docker does not respond monitor" + type = string + default = "true" +} + +variable "not_responding_message" { + description = "Custom message for Docker does not respond monitor" + type = string + default = "" +} + +variable "not_responding_threshold_warning" { + description = "Docker does not respond monitor (warning threshold)" + type = string + default = 3 +} + +variable "not_responding_no_data_timeframe" { + description = "Docker does not respond monitor no data timeframe" + type = string + default = 10 +} + +variable "not_responding_extra_tags" { + description = "Extra tags for Docker does not respond monitor" + type = list(string) + default = [] +} + +# +# Container Memory Usage +# +variable "memory_used_enabled" { + description = "Flag to enable Container Memory Usage monitor" + type = string + default = "false" +} + +variable "memory_used_message" { + description = "Custom message for the Container Memory Usage monitor" + type = string + default = "" +} + +variable "memory_used_time_aggregator" { + description = "Time aggregator for the Container Memory Usage monitor" + type = string + default = "min" +} + +variable "memory_used_timeframe" { + description = "Timeframe for the Container Memory Usage monitor" + type = string + default = "last_5m" +} + +variable "memory_used_threshold_warning" { + description = "Container Memory Usage warning threshold" + type = string + default = 85 +} + +variable "memory_used_threshold_critical" { + description = "Container Memory Usage critical threshold" + type = string + default = 90 +} + +variable "memory_used_extra_tags" { + description = "Extra tags for Container Memory Usage monitor" + type = list(string) + default = [] +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/docker/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/docker/modules.tf new file mode 100755 index 0000000..4038380 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/docker/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "docker" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/docker/monitors-docker.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/docker/monitors-docker.tf new file mode 100755 index 0000000..690b42b --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/docker/monitors-docker.tf @@ -0,0 +1,61 @@ +# +# Service Check +# +resource "datadog_monitor" "not_responding" { + count = var.not_responding_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Docker does not respond" + message = coalesce(var.not_responding_message, var.message) + type = "service check" + + query = < ${var.memory_used_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.memory_used_threshold_warning + critical = var.memory_used_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:docker", "provider:docker", "resource:docker", "team:claranet", "created-by:terraform"], var.memory_used_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/docker/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/docker/outputs.tf new file mode 100755 index 0000000..1fcd1b0 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/docker/outputs.tf @@ -0,0 +1,10 @@ +output "memory_used_id" { + description = "id for monitor memory_used" + value = datadog_monitor.memory_used.*.id +} + +output "not_responding_id" { + description = "id for monitor not_responding" + value = datadog_monitor.not_responding.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/docker/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/docker/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/docker/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ark/README.md b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ark/README.md new file mode 100755 index 0000000..d981b7d --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ark/README.md @@ -0,0 +1,107 @@ +# CAAS KUBERNETES ARK DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-caas-kubernetes-ark" { + source = "claranet/monitors/datadog//caas/kubernetes/ark" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Ark backup failed + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.ark_schedules_monitor](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [ark\_schedules\_enabled](#input\_ark\_schedules\_enabled) | Flag to enable Ark schedules monitor | `string` | `"true"` | no | +| [ark\_schedules\_extra\_tags](#input\_ark\_schedules\_extra\_tags) | Extra tags for Ark schedules monitor | `list(string)` | `[]` | no | +| [ark\_schedules\_monitor\_message](#input\_ark\_schedules\_monitor\_message) | Custom message for Ark schedules monitor | `string` | `""` | no | +| [ark\_schedules\_monitor\_no\_data\_timeframe](#input\_ark\_schedules\_monitor\_no\_data\_timeframe) | No data timeframe in minutes | `number` | `2880` | no | +| [ark\_schedules\_monitor\_timeframe](#input\_ark\_schedules\_monitor\_timeframe) | Monitor timeframe for Ark schedules monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1d"` | no | +| [environment](#input\_environment) | Architecture environment | `any` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [ark\_schedules\_monitor\_id](#output\_ark\_schedules\_monitor\_id) | id for monitor ark\_schedules\_monitor | +## Related documentation + +DataDog blog: https://www.datadoghq.com/blog/monitor-prometheus-metrics +Heptio Ark minimum release: https://github.com/heptio/ark/releases/tag/v0.9.0 + +## Ark annotations for Datadog + +``` +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + namespace: heptio-ark + name: ark +spec: + replicas: 1 + template: + metadata: + labels: + component: ark + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "8085" + prometheus.io/path: "/metrics" + ad.datadoghq.com/ark.check_names: |- + ["prometheus"] + ad.datadoghq.com/ark.init_configs: |- + [{}] + ad.datadoghq.com/ark.instances: |- + [ + { + "prometheus_url": "http://%%host%%:8085/metrics", + "namespace": "ark", + "metrics": ["ark_backup_*"], + "tags": ["dd_monitoring:enabled","dd_ark:enabled","env:prod"] + } + ] +``` diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ark/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ark/inputs.tf new file mode 100755 index 0000000..50f3560 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ark/inputs.tf @@ -0,0 +1,76 @@ +# Datadog global variables + +variable "environment" { + description = "Architecture environment" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# Datadog monitors variables + +variable "ark_schedules_monitor_message" { + description = "Custom message for Ark schedules monitor" + type = string + default = "" +} + +variable "ark_schedules_monitor_timeframe" { + description = "Monitor timeframe for Ark schedules monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1d" +} + +variable "ark_schedules_enabled" { + description = "Flag to enable Ark schedules monitor" + type = string + default = "true" +} + +variable "ark_schedules_extra_tags" { + description = "Extra tags for Ark schedules monitor" + type = list(string) + default = [] +} + +variable "ark_schedules_monitor_no_data_timeframe" { + description = "No data timeframe in minutes" + default = 2880 +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ark/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ark/modules.tf new file mode 100755 index 0000000..d3f43ff --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ark/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "ark" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ark/monitors-ark.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ark/monitors-ark.tf new file mode 100755 index 0000000..d41b417 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ark/monitors-ark.tf @@ -0,0 +1,30 @@ +resource "datadog_monitor" "ark_schedules_monitor" { + count = var.ark_schedules_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Ark backup failed" + type = "query alert" + message = coalesce(var.ark_schedules_monitor_message, var.message) + + query = < 1 +EOQ + + monitor_thresholds { + critical = 1 + warning = 0 + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + no_data_timeframe = var.ark_schedules_monitor_no_data_timeframe + + notify_no_data = var.notify_no_data + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:caas", "provider:prometheus", "resource:ark", "team:claranet", "created-by:terraform"], var.ark_schedules_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ark/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ark/outputs.tf new file mode 100755 index 0000000..1c588cd --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ark/outputs.tf @@ -0,0 +1,5 @@ +output "ark_schedules_monitor_id" { + description = "id for monitor ark_schedules_monitor" + value = datadog_monitor.ark_schedules_monitor.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ark/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ark/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ark/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/cluster/README.md b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/cluster/README.md new file mode 100755 index 0000000..9f14cbd --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/cluster/README.md @@ -0,0 +1,79 @@ +# CAAS KUBERNETES CLUSTER DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-caas-kubernetes-cluster" { + source = "claranet/monitors/datadog//caas/kubernetes/cluster" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Kubernetes API server does not respond + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.apiserver](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [apiserver\_enabled](#input\_apiserver\_enabled) | Flag to enable API server monitor | `string` | `"true"` | no | +| [apiserver\_extra\_tags](#input\_apiserver\_extra\_tags) | Extra tags for API server monitor | `list(string)` | `[]` | no | +| [apiserver\_message](#input\_apiserver\_message) | Custom message for API server monitor | `string` | `""` | no | +| [apiserver\_no\_data\_timeframe](#input\_apiserver\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [apiserver\_threshold\_warning](#input\_apiserver\_threshold\_warning) | API server monitor (warning threshold) | `string` | `3` | no | +| [environment](#input\_environment) | Architecture environment | `any` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [apiserver\_id](#output\_apiserver\_id) | id for monitor apiserver | +## Related documentation + +* [Datadog metrics](https://docs.datadoghq.com/agent/kubernetes/metrics/) +* [Datadog documentation](https://docs.datadoghq.com/integrations/kubernetes/) +* [Datadog Blog](https://www.datadoghq.com/blog/monitor-kubernetes-docker/) + +## Requirements + +* Datadog Agent > v6.6 diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/cluster/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/cluster/inputs.tf new file mode 100755 index 0000000..248b1f9 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/cluster/inputs.tf @@ -0,0 +1,77 @@ +# Datadog global variables + +variable "environment" { + description = "Architecture environment" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "apiserver_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# Datadog monitors variables + +variable "apiserver_enabled" { + description = "Flag to enable API server monitor" + type = string + default = "true" +} + +variable "apiserver_extra_tags" { + description = "Extra tags for API server monitor" + type = list(string) + default = [] +} + +variable "apiserver_message" { + description = "Custom message for API server monitor" + type = string + default = "" +} + +variable "apiserver_threshold_warning" { + description = "API server monitor (warning threshold)" + type = string + default = 3 +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/cluster/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/cluster/modules.tf new file mode 100755 index 0000000..a57cf43 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/cluster/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "kubernetes" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/cluster/monitors-k8s-cluster.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/cluster/monitors-k8s-cluster.tf new file mode 100755 index 0000000..6219dc3 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/cluster/monitors-k8s-cluster.tf @@ -0,0 +1,29 @@ +resource "datadog_monitor" "apiserver" { + count = var.apiserver_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Kubernetes API server does not respond" + message = coalesce(var.apiserver_message, var.message) + + type = "service check" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../../common/filter-tags | n/a | +| [filter-tags-4xx](#module\_filter-tags-4xx) | ../../../../common/filter-tags | n/a | +| [filter-tags-5xx](#module\_filter-tags-5xx) | ../../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.nginx_ingress_too_many_4xx](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.nginx_ingress_too_many_5xx](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [artificial\_requests\_count](#input\_artificial\_requests\_count) | Number of false requests used to mitigate false positive in case of low trafic | `number` | `5` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [ingress\_4xx\_enabled](#input\_ingress\_4xx\_enabled) | Flag to enable Ingress 4xx errors monitor | `string` | `"true"` | no | +| [ingress\_4xx\_extra\_tags](#input\_ingress\_4xx\_extra\_tags) | Extra tags for Ingress 4xx errors monitor | `list(string)` | `[]` | no | +| [ingress\_4xx\_message](#input\_ingress\_4xx\_message) | Message sent when an alert is triggered | `string` | `""` | no | +| [ingress\_4xx\_threshold\_critical](#input\_ingress\_4xx\_threshold\_critical) | 4xx critical threshold in percentage | `string` | `"40"` | no | +| [ingress\_4xx\_threshold\_warning](#input\_ingress\_4xx\_threshold\_warning) | 4xx warning threshold in percentage | `string` | `"20"` | no | +| [ingress\_4xx\_time\_aggregator](#input\_ingress\_4xx\_time\_aggregator) | Monitor aggregator for Ingress 4xx errors [available values: min, max or avg] | `string` | `"min"` | no | +| [ingress\_4xx\_timeframe](#input\_ingress\_4xx\_timeframe) | Monitor timeframe for Ingress 4xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [ingress\_5xx\_enabled](#input\_ingress\_5xx\_enabled) | Flag to enable Ingress 5xx errors monitor | `string` | `"true"` | no | +| [ingress\_5xx\_extra\_tags](#input\_ingress\_5xx\_extra\_tags) | Extra tags for Ingress 5xx errors monitor | `list(string)` | `[]` | no | +| [ingress\_5xx\_message](#input\_ingress\_5xx\_message) | Message sent when an alert is triggered | `string` | `""` | no | +| [ingress\_5xx\_threshold\_critical](#input\_ingress\_5xx\_threshold\_critical) | 5xx critical threshold in percentage | `string` | `"20"` | no | +| [ingress\_5xx\_threshold\_warning](#input\_ingress\_5xx\_threshold\_warning) | 5xx warning threshold in percentage | `string` | `"10"` | no | +| [ingress\_5xx\_time\_aggregator](#input\_ingress\_5xx\_time\_aggregator) | Monitor aggregator for Ingress 5xx errors [available values: min, max or avg] | `string` | `"min"` | no | +| [ingress\_5xx\_timeframe](#input\_ingress\_5xx\_timeframe) | Monitor timeframe for Ingress 5xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [nginx\_ingress\_too\_many\_4xx\_id](#output\_nginx\_ingress\_too\_many\_4xx\_id) | id for monitor nginx\_ingress\_too\_many\_4xx | +| [nginx\_ingress\_too\_many\_5xx\_id](#output\_nginx\_ingress\_too\_many\_5xx\_id) | id for monitor nginx\_ingress\_too\_many\_5xx | +## Related documentation + +DataDog blog: https://www.datadoghq.com/blog/monitor-prometheus-metrics +https://github.com/kubernetes/ingress-nginx/pull/423/commits/1d38e3a38425f08de2f75fcae13896a3fec4d144 + +## Nginx Ingress Controller setup + +This configuration and monitors only work for ingress controller version : +- \>= 0.10 because ingress is beta before that and metrics naming convention not stable +- <= 0.15 because ingress does not use VTS metrics since 0.16 +Enable the following flags in the Nginx Ingress Controller chart +controller.stats.enabled=true,controller.metrics.enabled=true +and the following Datadog agent configuration for each ingress controller: +``` +datadog: + confd: + prometheus.yaml: |- + #nginx_upstream_responses_total{ingress_class,namespace,server,status_code:{1xx,2xx,3xx,4xx,5xx},upstream} + #nginx_upstream_requests_total{ingress_class,namespace,server,upstream} + init_config: + instances: + # The prometheus endpoint to query from + - prometheus_url: http://nginx-ingress-controller-metrics:9913/metrics + # This is NOT the ingress namespace, it is the prefix that will be used for the custom metrics + namespace: nginx-ingress + # Filter on the following metrics only + metrics: + - "nginx_upstream_requests_total" + - "nginx_upstream_responses_total" + # Adapt the tags to the current convention and verify that the monitor will match + tags: + - dd_monitoring:enabled + - dd_ingress:enabled + - dd_ingress_class:nginx + - env:ENV +``` diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ingress/vts/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ingress/vts/inputs.tf new file mode 100755 index 0000000..d8820d2 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ingress/vts/inputs.tf @@ -0,0 +1,135 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +#Ingress + +variable "ingress_5xx_enabled" { + description = "Flag to enable Ingress 5xx errors monitor" + type = string + default = "true" +} + +variable "ingress_5xx_extra_tags" { + description = "Extra tags for Ingress 5xx errors monitor" + type = list(string) + default = [] +} + +variable "ingress_5xx_message" { + description = "Message sent when an alert is triggered" + default = "" +} + +variable "ingress_5xx_time_aggregator" { + description = "Monitor aggregator for Ingress 5xx errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "ingress_5xx_timeframe" { + description = "Monitor timeframe for Ingress 5xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "ingress_5xx_threshold_critical" { + type = string + default = "20" + description = "5xx critical threshold in percentage" +} + +variable "ingress_5xx_threshold_warning" { + type = string + default = "10" + description = "5xx warning threshold in percentage" +} + +variable "ingress_4xx_enabled" { + description = "Flag to enable Ingress 4xx errors monitor" + type = string + default = "true" +} + +variable "ingress_4xx_extra_tags" { + description = "Extra tags for Ingress 4xx errors monitor" + type = list(string) + default = [] +} + +variable "ingress_4xx_message" { + description = "Message sent when an alert is triggered" + default = "" +} + +variable "ingress_4xx_time_aggregator" { + description = "Monitor aggregator for Ingress 4xx errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "ingress_4xx_timeframe" { + description = "Monitor timeframe for Ingress 4xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "ingress_4xx_threshold_critical" { + type = string + default = "40" + description = "4xx critical threshold in percentage" +} + +variable "ingress_4xx_threshold_warning" { + type = string + default = "20" + description = "4xx warning threshold in percentage" +} + +variable "artificial_requests_count" { + default = 5 + description = "Number of false requests used to mitigate false positive in case of low trafic" +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ingress/vts/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ingress/vts/modules.tf new file mode 100755 index 0000000..1ce323a --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ingress/vts/modules.tf @@ -0,0 +1,35 @@ +module "filter-tags" { + source = "../../../../common/filter-tags" + + environment = var.environment + resource = "ingress" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags_excluded = ["upstream:upstream-default-backend"] +} + +module "filter-tags-5xx" { + source = "../../../../common/filter-tags" + + environment = var.environment + resource = "ingress" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["status_code:5xx"] + extra_tags_excluded = ["upstream:upstream-default-backend"] +} + +module "filter-tags-4xx" { + source = "../../../../common/filter-tags" + + environment = var.environment + resource = "ingress" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["status_code:4xx"] + extra_tags_excluded = ["upstream:upstream-default-backend"] +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ingress/vts/monitors-ingress.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ingress/vts/monitors-ingress.tf new file mode 100755 index 0000000..4ced3e7 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ingress/vts/monitors-ingress.tf @@ -0,0 +1,62 @@ +resource "datadog_monitor" "nginx_ingress_too_many_5xx" { + count = var.ingress_5xx_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Nginx Ingress 5xx errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.ingress_5xx_message, var.message) + type = "query alert" + + query = < ${var.ingress_5xx_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.ingress_5xx_threshold_warning + critical = var.ingress_5xx_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:prometheus", "resource:nginx-ingress-controller", "team:claranet", "created-by:terraform"], var.ingress_5xx_extra_tags) +} + +resource "datadog_monitor" "nginx_ingress_too_many_4xx" { + count = var.ingress_4xx_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Nginx Ingress 4xx errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.ingress_4xx_message, var.message) + type = "query alert" + + query = < ${var.ingress_4xx_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.ingress_4xx_threshold_warning + critical = var.ingress_4xx_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:prometheus", "resource:nginx-ingress-controller", "team:claranet", "created-by:terraform"], var.ingress_4xx_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ingress/vts/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ingress/vts/outputs.tf new file mode 100755 index 0000000..52bde5a --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ingress/vts/outputs.tf @@ -0,0 +1,10 @@ +output "nginx_ingress_too_many_4xx_id" { + description = "id for monitor nginx_ingress_too_many_4xx" + value = datadog_monitor.nginx_ingress_too_many_4xx.*.id +} + +output "nginx_ingress_too_many_5xx_id" { + description = "id for monitor nginx_ingress_too_many_5xx" + value = datadog_monitor.nginx_ingress_too_many_5xx.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ingress/vts/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ingress/vts/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/ingress/vts/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/node/README.md b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/node/README.md new file mode 100755 index 0000000..8dc15bd --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/node/README.md @@ -0,0 +1,152 @@ +# CAAS KUBERNETES NODE DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-caas-kubernetes-node" { + source = "claranet/monitors/datadog//caas/kubernetes/node" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Kubernetes Node Disk pressure +- Kubernetes Node Frequent unregister net device +- Kubernetes Node Kubelet API does not respond +- Kubernetes Node Kubelet sync loop that updates containers does not work +- Kubernetes Node Memory pressure +- Kubernetes Node not ready +- Kubernetes Node Out of disk +- Kubernetes Node unschedulable +- Kubernetes Node volume inodes usage +- Kubernetes Node volume space usage + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | +| [filter-tags-unschedulable](#module\_filter-tags-unschedulable) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.disk_out](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.disk_pressure](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.kubelet_ping](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.kubelet_syncloop](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.memory_pressure](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.node_unschedulable](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ready](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.unregister_net_device](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.volume_inodes](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.volume_space](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [disk\_out\_enabled](#input\_disk\_out\_enabled) | Flag to enable Out of disk monitor | `string` | `"true"` | no | +| [disk\_out\_extra\_tags](#input\_disk\_out\_extra\_tags) | Extra tags for Out of disk monitor | `list(string)` | `[]` | no | +| [disk\_out\_message](#input\_disk\_out\_message) | Custom message for Out of disk monitor | `string` | `""` | no | +| [disk\_out\_threshold\_warning](#input\_disk\_out\_threshold\_warning) | Out of disk monitor (warning threshold) | `string` | `3` | no | +| [disk\_pressure\_enabled](#input\_disk\_pressure\_enabled) | Flag to enable Disk pressure monitor | `string` | `"true"` | no | +| [disk\_pressure\_extra\_tags](#input\_disk\_pressure\_extra\_tags) | Extra tags for Disk pressure monitor | `list(string)` | `[]` | no | +| [disk\_pressure\_message](#input\_disk\_pressure\_message) | Custom message for Disk pressure monitor | `string` | `""` | no | +| [disk\_pressure\_threshold\_warning](#input\_disk\_pressure\_threshold\_warning) | Disk pressure monitor (warning threshold) | `string` | `3` | no | +| [environment](#input\_environment) | Architecture environment | `any` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [kubelet\_ping\_enabled](#input\_kubelet\_ping\_enabled) | Flag to enable Kubelet ping monitor | `string` | `"true"` | no | +| [kubelet\_ping\_extra\_tags](#input\_kubelet\_ping\_extra\_tags) | Extra tags for Kubelet ping monitor | `list(string)` | `[]` | no | +| [kubelet\_ping\_message](#input\_kubelet\_ping\_message) | Custom message for Kubelet ping monitor | `string` | `""` | no | +| [kubelet\_ping\_no\_data\_timeframe](#input\_kubelet\_ping\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [kubelet\_ping\_threshold\_warning](#input\_kubelet\_ping\_threshold\_warning) | Kubelet ping monitor (warning threshold) | `string` | `3` | no | +| [kubelet\_syncloop\_enabled](#input\_kubelet\_syncloop\_enabled) | Flag to enable Kubelet sync loop monitor | `string` | `"true"` | no | +| [kubelet\_syncloop\_extra\_tags](#input\_kubelet\_syncloop\_extra\_tags) | Extra tags for Kubelet sync loop monitor | `list(string)` | `[]` | no | +| [kubelet\_syncloop\_message](#input\_kubelet\_syncloop\_message) | Custom message for Kubelet sync loop monitor | `string` | `""` | no | +| [kubelet\_syncloop\_threshold\_warning](#input\_kubelet\_syncloop\_threshold\_warning) | Kubelet sync loop monitor (warning threshold) | `string` | `3` | no | +| [memory\_pressure\_enabled](#input\_memory\_pressure\_enabled) | Flag to enable Memory pressure monitor | `string` | `"true"` | no | +| [memory\_pressure\_extra\_tags](#input\_memory\_pressure\_extra\_tags) | Extra tags for Memory pressure monitor | `list(string)` | `[]` | no | +| [memory\_pressure\_message](#input\_memory\_pressure\_message) | Custom message for Memory pressure monitor | `string` | `""` | no | +| [memory\_pressure\_threshold\_warning](#input\_memory\_pressure\_threshold\_warning) | Memory pressure monitor (warning threshold) | `string` | `3` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [node\_unschedulable\_enabled](#input\_node\_unschedulable\_enabled) | Flag to enable node unschedulable monitor | `string` | `"true"` | no | +| [node\_unschedulable\_extra\_tags](#input\_node\_unschedulable\_extra\_tags) | Extra tags for node unschedulable monitor | `list(string)` | `[]` | no | +| [node\_unschedulable\_message](#input\_node\_unschedulable\_message) | Custom message for node unschedulable monitor | `string` | `""` | no | +| [node\_unschedulable\_time\_aggregator](#input\_node\_unschedulable\_time\_aggregator) | Monitor aggregator for node unschedulable [available values: min, max or avg] | `string` | `"min"` | no | +| [node\_unschedulable\_timeframe](#input\_node\_unschedulable\_timeframe) | Monitor timeframe for node unschedulable [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1h"` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [ready\_enabled](#input\_ready\_enabled) | Flag to enable Node ready monitor | `string` | `"true"` | no | +| [ready\_extra\_tags](#input\_ready\_extra\_tags) | Extra tags for Node ready monitor | `list(string)` | `[]` | no | +| [ready\_message](#input\_ready\_message) | Custom message for Node ready monitor | `string` | `""` | no | +| [ready\_threshold\_warning](#input\_ready\_threshold\_warning) | Node ready monitor (warning threshold) | `string` | `3` | no | +| [unregister\_net\_device\_enabled](#input\_unregister\_net\_device\_enabled) | Flag to enable Unregister net device monitor | `string` | `"true"` | no | +| [unregister\_net\_device\_extra\_tags](#input\_unregister\_net\_device\_extra\_tags) | Extra tags for Unregister net device monitor | `list(string)` | `[]` | no | +| [unregister\_net\_device\_message](#input\_unregister\_net\_device\_message) | Custom message for Unregister net device monitor | `string` | `""` | no | +| [unregister\_net\_device\_threshold\_critical](#input\_unregister\_net\_device\_threshold\_critical) | Unregister net device critical threshold | `number` | `3` | no | +| [unregister\_net\_device\_time\_aggregator](#input\_unregister\_net\_device\_time\_aggregator) | Monitor aggregator for Unregister net device [available values: min, max or avg] | `string` | `"min"` | no | +| [unregister\_net\_device\_timeframe](#input\_unregister\_net\_device\_timeframe) | Monitor timeframe for Unregister net device [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"15m"` | no | +| [volume\_inodes\_enabled](#input\_volume\_inodes\_enabled) | Flag to enable Volume inodes monitor | `string` | `"true"` | no | +| [volume\_inodes\_extra\_tags](#input\_volume\_inodes\_extra\_tags) | Extra tags for Volume inodes monitor | `list(string)` | `[]` | no | +| [volume\_inodes\_message](#input\_volume\_inodes\_message) | Custom message for Volume inodes monitor | `string` | `""` | no | +| [volume\_inodes\_threshold\_critical](#input\_volume\_inodes\_threshold\_critical) | Volume inodes critical threshold | `number` | `95` | no | +| [volume\_inodes\_threshold\_warning](#input\_volume\_inodes\_threshold\_warning) | Volume inodes warning threshold | `number` | `90` | no | +| [volume\_inodes\_time\_aggregator](#input\_volume\_inodes\_time\_aggregator) | Monitor aggregator for Volume inodes [available values: min, max or avg] | `string` | `"min"` | no | +| [volume\_inodes\_timeframe](#input\_volume\_inodes\_timeframe) | Monitor timeframe for Volume inodes [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [volume\_space\_enabled](#input\_volume\_space\_enabled) | Flag to enable Volume space monitor | `string` | `"true"` | no | +| [volume\_space\_extra\_tags](#input\_volume\_space\_extra\_tags) | Extra tags for Volume space monitor | `list(string)` | `[]` | no | +| [volume\_space\_message](#input\_volume\_space\_message) | Custom message for Volume space monitor | `string` | `""` | no | +| [volume\_space\_threshold\_critical](#input\_volume\_space\_threshold\_critical) | Volume space critical threshold | `number` | `95` | no | +| [volume\_space\_threshold\_warning](#input\_volume\_space\_threshold\_warning) | Volume space warning threshold | `number` | `90` | no | +| [volume\_space\_time\_aggregator](#input\_volume\_space\_time\_aggregator) | Monitor aggregator for Volume space [available values: min, max or avg] | `string` | `"min"` | no | +| [volume\_space\_timeframe](#input\_volume\_space\_timeframe) | Monitor timeframe for Volume space [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [disk\_out\_id](#output\_disk\_out\_id) | id for monitor disk\_out | +| [disk\_pressure\_id](#output\_disk\_pressure\_id) | id for monitor disk\_pressure | +| [kubelet\_ping\_id](#output\_kubelet\_ping\_id) | id for monitor kubelet\_ping | +| [kubelet\_syncloop\_id](#output\_kubelet\_syncloop\_id) | id for monitor kubelet\_syncloop | +| [memory\_pressure\_id](#output\_memory\_pressure\_id) | id for monitor memory\_pressure | +| [node\_unschedulable\_id](#output\_node\_unschedulable\_id) | id for monitor node\_unschedulable | +| [ready\_id](#output\_ready\_id) | id for monitor ready | +| [unregister\_net\_device\_id](#output\_unregister\_net\_device\_id) | id for monitor unregister\_net\_device | +| [volume\_inodes\_id](#output\_volume\_inodes\_id) | id for monitor volume\_inodes | +| [volume\_space\_id](#output\_volume\_space\_id) | id for monitor volume\_space | +## Related documentation + +* [Datadog metrics](https://docs.datadoghq.com/agent/kubernetes/metrics/) +* [Datadog documentation](https://docs.datadoghq.com/integrations/kubernetes/) +* [Datadog Blog](https://www.datadoghq.com/blog/monitor-kubernetes-docker/) + +## Requirements + +* Datadog Agent > v6.6 diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/node/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/node/inputs.tf new file mode 100755 index 0000000..f45bd96 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/node/inputs.tf @@ -0,0 +1,342 @@ +# Datadog global variables + +variable "environment" { + description = "Architecture environment" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "kubelet_ping_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# Datadog monitors variables + +variable "disk_pressure_enabled" { + description = "Flag to enable Disk pressure monitor" + type = string + default = "true" +} + +variable "disk_pressure_extra_tags" { + description = "Extra tags for Disk pressure monitor" + type = list(string) + default = [] +} + +variable "disk_pressure_message" { + description = "Custom message for Disk pressure monitor" + type = string + default = "" +} + +variable "disk_pressure_threshold_warning" { + description = "Disk pressure monitor (warning threshold)" + type = string + default = 3 +} + +variable "disk_out_enabled" { + description = "Flag to enable Out of disk monitor" + type = string + default = "true" +} + +variable "disk_out_extra_tags" { + description = "Extra tags for Out of disk monitor" + type = list(string) + default = [] +} + +variable "disk_out_message" { + description = "Custom message for Out of disk monitor" + type = string + default = "" +} + +variable "disk_out_threshold_warning" { + description = "Out of disk monitor (warning threshold)" + type = string + default = 3 +} + +variable "memory_pressure_enabled" { + description = "Flag to enable Memory pressure monitor" + type = string + default = "true" +} + +variable "memory_pressure_extra_tags" { + description = "Extra tags for Memory pressure monitor" + type = list(string) + default = [] +} + +variable "memory_pressure_message" { + description = "Custom message for Memory pressure monitor" + type = string + default = "" +} + +variable "memory_pressure_threshold_warning" { + description = "Memory pressure monitor (warning threshold)" + type = string + default = 3 +} + +variable "ready_enabled" { + description = "Flag to enable Node ready monitor" + type = string + default = "true" +} + +variable "ready_extra_tags" { + description = "Extra tags for Node ready monitor" + type = list(string) + default = [] +} + +variable "ready_message" { + description = "Custom message for Node ready monitor" + type = string + default = "" +} + +variable "ready_threshold_warning" { + description = "Node ready monitor (warning threshold)" + type = string + default = 3 +} + +variable "kubelet_ping_enabled" { + description = "Flag to enable Kubelet ping monitor" + type = string + default = "true" +} + +variable "kubelet_ping_extra_tags" { + description = "Extra tags for Kubelet ping monitor" + type = list(string) + default = [] +} + +variable "kubelet_ping_message" { + description = "Custom message for Kubelet ping monitor" + type = string + default = "" +} + +variable "kubelet_ping_threshold_warning" { + description = "Kubelet ping monitor (warning threshold)" + type = string + default = 3 +} + +variable "kubelet_syncloop_enabled" { + description = "Flag to enable Kubelet sync loop monitor" + type = string + default = "true" +} + +variable "kubelet_syncloop_extra_tags" { + description = "Extra tags for Kubelet sync loop monitor" + type = list(string) + default = [] +} + +variable "kubelet_syncloop_message" { + description = "Custom message for Kubelet sync loop monitor" + type = string + default = "" +} + +variable "kubelet_syncloop_threshold_warning" { + description = "Kubelet sync loop monitor (warning threshold)" + type = string + default = 3 +} + +variable "unregister_net_device_enabled" { + description = "Flag to enable Unregister net device monitor" + type = string + default = "true" +} + +variable "unregister_net_device_extra_tags" { + description = "Extra tags for Unregister net device monitor" + type = list(string) + default = [] +} + +variable "unregister_net_device_message" { + description = "Custom message for Unregister net device monitor" + type = string + default = "" +} + +variable "unregister_net_device_time_aggregator" { + description = "Monitor aggregator for Unregister net device [available values: min, max or avg]" + type = string + default = "min" +} + +variable "unregister_net_device_timeframe" { + description = "Monitor timeframe for Unregister net device [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "15m" +} + +variable "unregister_net_device_threshold_critical" { + default = 3 + description = "Unregister net device critical threshold" +} + +variable "node_unschedulable_enabled" { + description = "Flag to enable node unschedulable monitor" + type = string + default = "true" +} + +variable "node_unschedulable_extra_tags" { + description = "Extra tags for node unschedulable monitor" + type = list(string) + default = [] +} + +variable "node_unschedulable_message" { + description = "Custom message for node unschedulable monitor" + type = string + default = "" +} + +variable "node_unschedulable_time_aggregator" { + description = "Monitor aggregator for node unschedulable [available values: min, max or avg]" + type = string + default = "min" +} + +variable "node_unschedulable_timeframe" { + description = "Monitor timeframe for node unschedulable [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1h" +} + +variable "volume_space_enabled" { + description = "Flag to enable Volume space monitor" + type = string + default = "true" +} + +variable "volume_space_extra_tags" { + description = "Extra tags for Volume space monitor" + type = list(string) + default = [] +} + +variable "volume_space_message" { + description = "Custom message for Volume space monitor" + type = string + default = "" +} + +variable "volume_space_time_aggregator" { + description = "Monitor aggregator for Volume space [available values: min, max or avg]" + type = string + default = "min" +} + +variable "volume_space_timeframe" { + description = "Monitor timeframe for Volume space [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "volume_space_threshold_critical" { + default = 95 + description = "Volume space critical threshold" +} + +variable "volume_space_threshold_warning" { + default = 90 + description = "Volume space warning threshold" +} + +variable "volume_inodes_enabled" { + description = "Flag to enable Volume inodes monitor" + type = string + default = "true" +} + +variable "volume_inodes_extra_tags" { + description = "Extra tags for Volume inodes monitor" + type = list(string) + default = [] +} + +variable "volume_inodes_message" { + description = "Custom message for Volume inodes monitor" + type = string + default = "" +} + +variable "volume_inodes_time_aggregator" { + description = "Monitor aggregator for Volume inodes [available values: min, max or avg]" + type = string + default = "min" +} + +variable "volume_inodes_timeframe" { + description = "Monitor timeframe for Volume inodes [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "volume_inodes_threshold_critical" { + default = 95 + description = "Volume inodes critical threshold" +} + +variable "volume_inodes_threshold_warning" { + default = 90 + description = "Volume inodes warning threshold" +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/node/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/node/modules.tf new file mode 100755 index 0000000..20f05b0 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/node/modules.tf @@ -0,0 +1,21 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "kubernetes" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + +module "filter-tags-unschedulable" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "kubernetes" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["status:unschedulable"] +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/node/monitors-k8s-node.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/node/monitors-k8s-node.tf new file mode 100755 index 0000000..def810c --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/node/monitors-k8s-node.tf @@ -0,0 +1,275 @@ +resource "datadog_monitor" "disk_pressure" { + count = var.disk_pressure_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Kubernetes Node Disk pressure" + message = coalesce(var.disk_pressure_message, var.message) + type = "service check" + + query = < ${var.unregister_net_device_threshold_critical} +EOQ + + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + + tags = concat(["env:${var.environment}", "type:caas", "provider:kubernetes", "resource:kubernetes-node", "team:claranet", "created-by:terraform"], var.unregister_net_device_extra_tags) +} + +resource "datadog_monitor" "node_unschedulable" { + count = var.node_unschedulable_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Kubernetes Node unschedulable" + message = coalesce(var.node_unschedulable_message, var.message) + type = "metric alert" + + query = < 0 +EOQ + + monitor_thresholds { + critical = 0 + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:kubernetes", "resource:kubernetes-node", "team:claranet", "created-by:terraform"], var.node_unschedulable_extra_tags) +} + +resource "datadog_monitor" "volume_space" { + count = var.volume_space_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Kubernetes Node volume space usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.volume_space_message, var.message) + type = "query alert" + + query = < ${var.volume_space_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.volume_space_threshold_critical + warning = var.volume_space_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:kubernetes", "resource:kubernetes-node", "team:claranet", "created-by:terraform"], var.volume_space_extra_tags) +} + +resource "datadog_monitor" "volume_inodes" { + count = var.volume_inodes_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Kubernetes Node volume inodes usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.volume_inodes_message, var.message) + type = "query alert" + + query = < ${var.volume_inodes_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.volume_inodes_threshold_critical + warning = var.volume_inodes_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:kubernetes", "resource:kubernetes-node", "team:claranet", "created-by:terraform"], var.volume_inodes_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/node/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/node/outputs.tf new file mode 100755 index 0000000..553a82e --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/node/outputs.tf @@ -0,0 +1,50 @@ +output "disk_out_id" { + description = "id for monitor disk_out" + value = datadog_monitor.disk_out.*.id +} + +output "disk_pressure_id" { + description = "id for monitor disk_pressure" + value = datadog_monitor.disk_pressure.*.id +} + +output "kubelet_ping_id" { + description = "id for monitor kubelet_ping" + value = datadog_monitor.kubelet_ping.*.id +} + +output "kubelet_syncloop_id" { + description = "id for monitor kubelet_syncloop" + value = datadog_monitor.kubelet_syncloop.*.id +} + +output "memory_pressure_id" { + description = "id for monitor memory_pressure" + value = datadog_monitor.memory_pressure.*.id +} + +output "node_unschedulable_id" { + description = "id for monitor node_unschedulable" + value = datadog_monitor.node_unschedulable.*.id +} + +output "ready_id" { + description = "id for monitor ready" + value = datadog_monitor.ready.*.id +} + +output "unregister_net_device_id" { + description = "id for monitor unregister_net_device" + value = datadog_monitor.unregister_net_device.*.id +} + +output "volume_inodes_id" { + description = "id for monitor volume_inodes" + value = datadog_monitor.volume_inodes.*.id +} + +output "volume_space_id" { + description = "id for monitor volume_space" + value = datadog_monitor.volume_space.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/node/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/node/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/node/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/pod/README.md b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/pod/README.md new file mode 100755 index 0000000..947267f --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/pod/README.md @@ -0,0 +1,101 @@ +# CAAS KUBERNETES POD DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-caas-kubernetes-pod" { + source = "claranet/monitors/datadog//caas/kubernetes/pod" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Kubernetes Pod phase status failed +- Kubernetes Pod terminated abnormally +- Kubernetes Pod waiting errors + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | +| [filter-tags-nocontainercreating](#module\_filter-tags-nocontainercreating) | ../../../common/filter-tags | n/a | +| [filter-tags-phase](#module\_filter-tags-phase) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.error](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.pod_phase_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.terminated](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `any` | n/a | yes | +| [error\_enabled](#input\_error\_enabled) | Flag to enable Pod errors monitor | `string` | `"true"` | no | +| [error\_extra\_tags](#input\_error\_extra\_tags) | Extra tags for Pod errors monitor | `list(string)` | `[]` | no | +| [error\_message](#input\_error\_message) | Custom message for Pod errors monitor | `string` | `""` | no | +| [error\_threshold\_critical](#input\_error\_threshold\_critical) | error critical threshold | `number` | `0.5` | no | +| [error\_threshold\_warning](#input\_error\_threshold\_warning) | error warning threshold | `number` | `0` | no | +| [error\_time\_aggregator](#input\_error\_time\_aggregator) | Monitor aggregator for Pod errors [available values: min, max or avg] | `string` | `"min"` | no | +| [error\_timeframe](#input\_error\_timeframe) | Monitor timeframe for Pod errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [pod\_phase\_status\_enabled](#input\_pod\_phase\_status\_enabled) | Flag to enable Pod phase status monitor | `string` | `"true"` | no | +| [pod\_phase\_status\_extra\_tags](#input\_pod\_phase\_status\_extra\_tags) | Extra tags for Pod phase status monitor | `list(string)` | `[]` | no | +| [pod\_phase\_status\_message](#input\_pod\_phase\_status\_message) | Custom message for Pod phase status monitor | `string` | `""` | no | +| [pod\_phase\_status\_time\_aggregator](#input\_pod\_phase\_status\_time\_aggregator) | Monitor aggregator for Pod phase status [available values: min, max or avg] | `string` | `"max"` | no | +| [pod\_phase\_status\_timeframe](#input\_pod\_phase\_status\_timeframe) | Monitor timeframe for Pod phase status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [terminated\_enabled](#input\_terminated\_enabled) | Flag to enable Pod terminated monitor | `string` | `"true"` | no | +| [terminated\_extra\_tags](#input\_terminated\_extra\_tags) | Extra tags for Pod terminated monitor | `list(string)` | `[]` | no | +| [terminated\_message](#input\_terminated\_message) | Custom message for Pod terminated monitor | `string` | `""` | no | +| [terminated\_threshold\_critical](#input\_terminated\_threshold\_critical) | terminated critical threshold | `number` | `0.5` | no | +| [terminated\_threshold\_warning](#input\_terminated\_threshold\_warning) | terminated warning threshold | `number` | `0` | no | +| [terminated\_time\_aggregator](#input\_terminated\_time\_aggregator) | Monitor aggregator for Pod terminated [available values: min, max or avg] | `string` | `"sum"` | no | +| [terminated\_timeframe](#input\_terminated\_timeframe) | Monitor timeframe for Pod terminated [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_10m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [error\_id](#output\_error\_id) | id for monitor error | +| [pod\_phase\_status\_id](#output\_pod\_phase\_status\_id) | id for monitor pod\_phase\_status | +| [terminated\_id](#output\_terminated\_id) | id for monitor terminated | +## Related documentation + +* [Datadog metrics](https://docs.datadoghq.com/agent/kubernetes/metrics/) +* [Datadog documentation](https://docs.datadoghq.com/integrations/kubernetes/) +* [Datadog Blog](https://www.datadoghq.com/blog/monitor-kubernetes-docker/) + +## Requirements + +* Datadog Agent > v7.2 diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/pod/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/pod/inputs.tf new file mode 100755 index 0000000..cdf6687 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/pod/inputs.tf @@ -0,0 +1,157 @@ +# Datadog global variables + +variable "environment" { + description = "Architecture environment" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# Datadog monitors variables + +variable "pod_phase_status_enabled" { + description = "Flag to enable Pod phase status monitor" + type = string + default = "true" +} + +variable "pod_phase_status_extra_tags" { + description = "Extra tags for Pod phase status monitor" + type = list(string) + default = [] +} + +variable "pod_phase_status_message" { + description = "Custom message for Pod phase status monitor" + type = string + default = "" +} + +variable "pod_phase_status_time_aggregator" { + description = "Monitor aggregator for Pod phase status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "pod_phase_status_timeframe" { + description = "Monitor timeframe for Pod phase status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "error_enabled" { + description = "Flag to enable Pod errors monitor" + type = string + default = "true" +} + +variable "error_extra_tags" { + description = "Extra tags for Pod errors monitor" + type = list(string) + default = [] +} + +variable "error_message" { + description = "Custom message for Pod errors monitor" + type = string + default = "" +} + +variable "error_time_aggregator" { + description = "Monitor aggregator for Pod errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "error_timeframe" { + description = "Monitor timeframe for Pod errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "error_threshold_critical" { + default = 0.5 + description = "error critical threshold" +} + +variable "error_threshold_warning" { + default = 0 + description = "error warning threshold" +} + +variable "terminated_enabled" { + description = "Flag to enable Pod terminated monitor" + type = string + default = "true" +} + +variable "terminated_extra_tags" { + description = "Extra tags for Pod terminated monitor" + type = list(string) + default = [] +} + +variable "terminated_message" { + description = "Custom message for Pod terminated monitor" + type = string + default = "" +} + +variable "terminated_time_aggregator" { + description = "Monitor aggregator for Pod terminated [available values: min, max or avg]" + type = string + default = "sum" +} + +variable "terminated_timeframe" { + description = "Monitor timeframe for Pod terminated [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_10m" +} + +variable "terminated_threshold_critical" { + default = 0.5 + description = "terminated critical threshold" +} + +variable "terminated_threshold_warning" { + default = 0 + description = "terminated warning threshold" +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/pod/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/pod/modules.tf new file mode 100755 index 0000000..eb818f5 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/pod/modules.tf @@ -0,0 +1,32 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "kubernetes" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + +module "filter-tags-phase" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "kubernetes" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags_excluded = ["phase:pending,phase:running,phase:succeeded,phase:unknown"] +} + +module "filter-tags-nocontainercreating" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "kubernetes" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags_excluded = ["reason:containercreating"] +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/pod/monitors-k8s-pod.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/pod/monitors-k8s-pod.tf new file mode 100755 index 0000000..53da50f --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/pod/monitors-k8s-pod.tf @@ -0,0 +1,89 @@ +resource "datadog_monitor" "pod_phase_status" { + count = var.pod_phase_status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Kubernetes Pod phase status failed" + message = coalesce(var.pod_phase_status_message, var.message) + type = "metric alert" + + query = < 0 +EOQ + + monitor_thresholds { + critical = 0 + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:kubernetes", "resource:kubernetes-pod", "team:claranet", "created-by:terraform"], var.pod_phase_status_extra_tags) +} + +resource "datadog_monitor" "error" { + count = var.error_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Kubernetes Pod waiting errors" + message = coalesce(var.error_message, var.message) + type = "query alert" + + query = < ${var.error_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.error_threshold_critical + warning = var.error_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:kubernetes", "resource:kubernetes-pod", "team:claranet", "created-by:terraform"], var.error_extra_tags) +} + +resource "datadog_monitor" "terminated" { + count = var.terminated_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Kubernetes Pod terminated abnormally" + message = coalesce(var.terminated_message, var.message) + type = "query alert" + + query = < ${var.terminated_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.terminated_threshold_critical + warning = var.terminated_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:kubernetes", "resource:kubernetes-pod", "team:claranet", "created-by:terraform"], var.terminated_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/pod/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/pod/outputs.tf new file mode 100755 index 0000000..1e71580 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/pod/outputs.tf @@ -0,0 +1,15 @@ +output "error_id" { + description = "id for monitor error" + value = datadog_monitor.error.*.id +} + +output "pod_phase_status_id" { + description = "id for monitor pod_phase_status" + value = datadog_monitor.pod_phase_status.*.id +} + +output "terminated_id" { + description = "id for monitor terminated" + value = datadog_monitor.terminated.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/pod/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/pod/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/pod/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/velero/README.md b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/velero/README.md new file mode 100755 index 0000000..7df2d36 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/velero/README.md @@ -0,0 +1,176 @@ +# CAAS KUBERNETES VELERO DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-caas-kubernetes-velero" { + source = "claranet/monitors/datadog//caas/kubernetes/velero" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Velero backup deletion failure +- Velero backup failure +- Velero backup partial failure +- Velero scheduled backup missing +- Velero volume snapshot failure + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | +| [filter-tags-scheduled-backup](#module\_filter-tags-scheduled-backup) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.velero_backup_deletion_failure](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.velero_backup_failure](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.velero_backup_partial_failure](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.velero_scheduled_backup_missing](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.velero_volume_snapshot_failure](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `any` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [velero\_backup\_deletion\_failure\_enabled](#input\_velero\_backup\_deletion\_failure\_enabled) | Flag to enable Velero backup deletion failure monitor | `string` | `"true"` | no | +| [velero\_backup\_deletion\_failure\_extra\_tags](#input\_velero\_backup\_deletion\_failure\_extra\_tags) | Extra tags for Velero backup deletion failure monitor | `list(string)` | `[]` | no | +| [velero\_backup\_deletion\_failure\_monitor\_message](#input\_velero\_backup\_deletion\_failure\_monitor\_message) | Custom message for Velero backup deletion failure monitor | `string` | `""` | no | +| [velero\_backup\_deletion\_failure\_monitor\_timeframe](#input\_velero\_backup\_deletion\_failure\_monitor\_timeframe) | Monitor timeframe for Velero backup deletion failure monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1d"` | no | +| [velero\_backup\_failure\_enabled](#input\_velero\_backup\_failure\_enabled) | Flag to enable Velero backup failure monitor | `string` | `"true"` | no | +| [velero\_backup\_failure\_extra\_tags](#input\_velero\_backup\_failure\_extra\_tags) | Extra tags for Velero backup failure monitor | `list(string)` | `[]` | no | +| [velero\_backup\_failure\_monitor\_message](#input\_velero\_backup\_failure\_monitor\_message) | Custom message for Velero backup failure monitor | `string` | `""` | no | +| [velero\_backup\_failure\_monitor\_timeframe](#input\_velero\_backup\_failure\_monitor\_timeframe) | Monitor timeframe for Velero backup failure monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1d"` | no | +| [velero\_backup\_partial\_failure\_enabled](#input\_velero\_backup\_partial\_failure\_enabled) | Flag to enable Velero backup partial failure monitor | `string` | `"true"` | no | +| [velero\_backup\_partial\_failure\_extra\_tags](#input\_velero\_backup\_partial\_failure\_extra\_tags) | Extra tags for Velero backup partial failure monitor | `list(string)` | `[]` | no | +| [velero\_backup\_partial\_failure\_monitor\_message](#input\_velero\_backup\_partial\_failure\_monitor\_message) | Custom message for Velero backup partial failure monitor | `string` | `""` | no | +| [velero\_backup\_partial\_failure\_monitor\_timeframe](#input\_velero\_backup\_partial\_failure\_monitor\_timeframe) | Monitor timeframe for Velero backup partial failure monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1d"` | no | +| [velero\_scheduled\_backup\_missing\_enabled](#input\_velero\_scheduled\_backup\_missing\_enabled) | Flag to enable Velero scheduled backup missing monitor | `string` | `"true"` | no | +| [velero\_scheduled\_backup\_missing\_extra\_tags](#input\_velero\_scheduled\_backup\_missing\_extra\_tags) | Extra tags for Velero scheduled backup missing monitor | `list(string)` | `[]` | no | +| [velero\_scheduled\_backup\_missing\_monitor\_message](#input\_velero\_scheduled\_backup\_missing\_monitor\_message) | Custom message for Velero scheduled backup missing monitor | `string` | `""` | no | +| [velero\_scheduled\_backup\_missing\_monitor\_no\_data\_timeframe](#input\_velero\_scheduled\_backup\_missing\_monitor\_no\_data\_timeframe) | No data timeframe in minutes | `number` | `2880` | no | +| [velero\_scheduled\_backup\_missing\_monitor\_timeframe](#input\_velero\_scheduled\_backup\_missing\_monitor\_timeframe) | Monitor timeframe for Velero scheduled backup missing monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1d"` | no | +| [velero\_volume\_snapshot\_failure\_enabled](#input\_velero\_volume\_snapshot\_failure\_enabled) | Flag to enable Velero volume snapshot failure monitor | `string` | `"true"` | no | +| [velero\_volume\_snapshot\_failure\_extra\_tags](#input\_velero\_volume\_snapshot\_failure\_extra\_tags) | Extra tags for Velero volume snapshot failure monitor | `list(string)` | `[]` | no | +| [velero\_volume\_snapshot\_failure\_monitor\_message](#input\_velero\_volume\_snapshot\_failure\_monitor\_message) | Custom message for Velero volume snapshot failure monitor | `string` | `""` | no | +| [velero\_volume\_snapshot\_failure\_monitor\_timeframe](#input\_velero\_volume\_snapshot\_failure\_monitor\_timeframe) | Monitor timeframe for Velero volume snapshot failure monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1d"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [velero\_backup\_deletion\_failure\_id](#output\_velero\_backup\_deletion\_failure\_id) | id for monitor velero\_backup\_deletion\_failure | +| [velero\_backup\_failure\_id](#output\_velero\_backup\_failure\_id) | id for monitor velero\_backup\_failure | +| [velero\_backup\_partial\_failure\_id](#output\_velero\_backup\_partial\_failure\_id) | id for monitor velero\_backup\_partial\_failure | +| [velero\_scheduled\_backup\_missing\_id](#output\_velero\_scheduled\_backup\_missing\_id) | id for monitor velero\_scheduled\_backup\_missing | +| [velero\_volume\_snapshot\_failure\_id](#output\_velero\_volume\_snapshot\_failure\_id) | id for monitor velero\_volume\_snapshot\_failure | +## Related documentation + +Documentation for Datadog prometheus intergration: https://docs.datadoghq.com/integrations/prometheus/ +Documentation for Datadog OpenMetrics integration: https://docs.datadoghq.com/integrations/openmetrics/ +Documentation for Datadog autodiscovery: https://docs.datadoghq.com/agent/autodiscovery/clusterchecks/ + +### How to configure Datadog agent for these monitors ? +You can configure Datadog agent by autodiscovery pod annotations or by configuration file. + +#### Configuration by autodiscovery pod annotations +Add these annotations to Velero pods: + +``` +podAnnotations: { + "ad.datadoghq.com/velero.check_names": '["openmetrics"]', + "ad.datadoghq.com/velero.init_configs": '[{}]', + "ad.datadoghq.com/velero.instances": '[{"prometheus_url": "http://%%host%%:8085/metrics", "namespace": "velero", "metrics": ["velero*"]}]' +} +``` + +#### Configuration by configuration file +Example of `openmetrics.d/conf.yaml`: + +``` +init_config: + +instances: + + ## @param prometheus_url - string - required + ## The URL where your application metrics are exposed by Prometheus. + # + - prometheus_url: http://velero.velero.svc.cluster.local:8085/metrics + + ## @param namespace - string - required + ## The namespace to be prepended to all metrics. + # + namespace: "velero" + + ## @param metrics - list of strings - required + ## List of metrics to be fetched from the prometheus endpoint, if there's a + ## value it'll be renamed. This list should contain at least one metric + # + metrics: + - velero* +``` + +### How to monitor multiple schedule witch have different frequencies ? + +If you have multiple Velero schedules with different frequencies, you must duplicate the default example module declaration specifying right timeframes and disabling others common monitors. + +For instance, for an hourly schedule you can uncomment this block: + +``` +#module "datadog-monitors-caas-kubernetes-velero" { +# source = "claranet/monitors/datadog//caas/kubernetes/velero" +# version = "{revision}" +# +# environment = var.environment +# message = module.datadog-message-alerting.alerting-message +#} + +#module "datadog-monitors-caas-kubernetes-velero-hourly" { +# source = "claranet/monitors/datadog//caas/kubernetes/velero" +# version = "{revision}" +# +# environment = var.environment +# message = module.datadog-message-alerting.alerting-message +# +# velero_scheduled_backup_missing_monitor_timeframe = "last_1h" +# velero_scheduled_backup_missing_monitor_no_data_timeframe = 120 +# velero_backup_failure_enabled = false +# velero_backup_partial_failure_enabled = false +# velero_backup_deletion_failure_enabled = false +# velero_volume_snapshot_failure_enabled = false +#} +``` + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/velero/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/velero/inputs.tf new file mode 100755 index 0000000..755cd6a --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/velero/inputs.tf @@ -0,0 +1,171 @@ +# Datadog global variables + +variable "environment" { + description = "Architecture environment" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# Datadog monitors variables + +variable "velero_scheduled_backup_missing_monitor_message" { + description = "Custom message for Velero scheduled backup missing monitor" + type = string + default = "" +} + +variable "velero_scheduled_backup_missing_monitor_timeframe" { + description = "Monitor timeframe for Velero scheduled backup missing monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1d" +} + +variable "velero_scheduled_backup_missing_enabled" { + description = "Flag to enable Velero scheduled backup missing monitor" + type = string + default = "true" +} + +variable "velero_scheduled_backup_missing_extra_tags" { + description = "Extra tags for Velero scheduled backup missing monitor" + type = list(string) + default = [] +} + +variable "velero_scheduled_backup_missing_monitor_no_data_timeframe" { + description = "No data timeframe in minutes" + default = 2880 +} + +variable "velero_backup_failure_monitor_message" { + description = "Custom message for Velero backup failure monitor" + type = string + default = "" +} + +variable "velero_backup_failure_monitor_timeframe" { + description = "Monitor timeframe for Velero backup failure monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1d" +} + +variable "velero_backup_failure_enabled" { + description = "Flag to enable Velero backup failure monitor" + type = string + default = "true" +} + +variable "velero_backup_failure_extra_tags" { + description = "Extra tags for Velero backup failure monitor" + type = list(string) + default = [] +} + +variable "velero_backup_partial_failure_monitor_message" { + description = "Custom message for Velero backup partial failure monitor" + type = string + default = "" +} + +variable "velero_backup_partial_failure_monitor_timeframe" { + description = "Monitor timeframe for Velero backup partial failure monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1d" +} + +variable "velero_backup_partial_failure_enabled" { + description = "Flag to enable Velero backup partial failure monitor" + type = string + default = "true" +} + +variable "velero_backup_partial_failure_extra_tags" { + description = "Extra tags for Velero backup partial failure monitor" + type = list(string) + default = [] +} + +variable "velero_backup_deletion_failure_monitor_message" { + description = "Custom message for Velero backup deletion failure monitor" + type = string + default = "" +} + +variable "velero_backup_deletion_failure_monitor_timeframe" { + description = "Monitor timeframe for Velero backup deletion failure monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1d" +} + +variable "velero_backup_deletion_failure_enabled" { + description = "Flag to enable Velero backup deletion failure monitor" + type = string + default = "true" +} + +variable "velero_backup_deletion_failure_extra_tags" { + description = "Extra tags for Velero backup deletion failure monitor" + type = list(string) + default = [] +} + +variable "velero_volume_snapshot_failure_monitor_message" { + description = "Custom message for Velero volume snapshot failure monitor" + type = string + default = "" +} + +variable "velero_volume_snapshot_failure_monitor_timeframe" { + description = "Monitor timeframe for Velero volume snapshot failure monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1d" +} + +variable "velero_volume_snapshot_failure_enabled" { + description = "Flag to enable Velero volume snapshot failure monitor" + type = string + default = "true" +} + +variable "velero_volume_snapshot_failure_extra_tags" { + description = "Extra tags for Velero volume snapshot failure monitor" + type = list(string) + default = [] +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/velero/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/velero/modules.tf new file mode 100755 index 0000000..c1cb2b3 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/velero/modules.tf @@ -0,0 +1,20 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "velero" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + +module "filter-tags-scheduled-backup" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "velero" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags_excluded = ["schedule:"] +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/velero/monitors-velero.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/velero/monitors-velero.tf new file mode 100755 index 0000000..12b0539 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/velero/monitors-velero.tf @@ -0,0 +1,145 @@ +resource "datadog_monitor" "velero_scheduled_backup_missing" { + count = var.velero_scheduled_backup_missing_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Velero scheduled backup missing" + type = "query alert" + message = coalesce(var.velero_scheduled_backup_missing_monitor_message, var.message) + + query = < 1 +EOQ + + monitor_thresholds { + critical = 1 + warning = 0 + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:openmetrics", "resource:velero", "team:claranet", "created-by:terraform"], var.velero_backup_failure_extra_tags) +} + +resource "datadog_monitor" "velero_backup_partial_failure" { + count = var.velero_backup_partial_failure_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Velero backup partial failure" + type = "query alert" + message = coalesce(var.velero_backup_partial_failure_monitor_message, var.message) + + query = < 1 +EOQ + + monitor_thresholds { + critical = 1 + warning = 0 + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:openmetrics", "resource:velero", "team:claranet", "created-by:terraform"], var.velero_backup_partial_failure_extra_tags) +} + +resource "datadog_monitor" "velero_backup_deletion_failure" { + count = var.velero_backup_deletion_failure_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Velero backup deletion failure" + type = "query alert" + message = coalesce(var.velero_backup_deletion_failure_monitor_message, var.message) + + query = < 1 +EOQ + + monitor_thresholds { + critical = 1 + warning = 0 + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:openmetrics", "resource:velero", "team:claranet", "created-by:terraform"], var.velero_backup_deletion_failure_extra_tags) +} + +resource "datadog_monitor" "velero_volume_snapshot_failure" { + count = var.velero_volume_snapshot_failure_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Velero volume snapshot failure" + type = "query alert" + message = coalesce(var.velero_volume_snapshot_failure_monitor_message, var.message) + + query = < 1 +EOQ + + monitor_thresholds { + critical = 1 + warning = 0 + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:openmetrics", "resource:velero", "team:claranet", "created-by:terraform"], var.velero_volume_snapshot_failure_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/velero/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/velero/outputs.tf new file mode 100755 index 0000000..992a26b --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/velero/outputs.tf @@ -0,0 +1,25 @@ +output "velero_backup_deletion_failure_id" { + description = "id for monitor velero_backup_deletion_failure" + value = datadog_monitor.velero_backup_deletion_failure.*.id +} + +output "velero_backup_failure_id" { + description = "id for monitor velero_backup_failure" + value = datadog_monitor.velero_backup_failure.*.id +} + +output "velero_backup_partial_failure_id" { + description = "id for monitor velero_backup_partial_failure" + value = datadog_monitor.velero_backup_partial_failure.*.id +} + +output "velero_scheduled_backup_missing_id" { + description = "id for monitor velero_scheduled_backup_missing" + value = datadog_monitor.velero_scheduled_backup_missing.*.id +} + +output "velero_volume_snapshot_failure_id" { + description = "id for monitor velero_volume_snapshot_failure" + value = datadog_monitor.velero_volume_snapshot_failure.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/velero/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/velero/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/velero/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/workload/README.md b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/workload/README.md new file mode 100755 index 0000000..1503175 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/workload/README.md @@ -0,0 +1,112 @@ +# CAAS KUBERNETES WORKLOAD DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-caas-kubernetes-workload" { + source = "claranet/monitors/datadog//caas/kubernetes/workload" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Kubernetes Available replicas +- Kubernetes cronjob scheduling failed +- Kubernetes Current replicas +- Kubernetes job failed +- Kubernetes Ready replicas + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cronjob](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.job](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.replica_available](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.replica_current](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.replica_ready](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cronjob\_enabled](#input\_cronjob\_enabled) | Flag to enable Cronjob monitor | `string` | `"true"` | no | +| [cronjob\_extra\_tags](#input\_cronjob\_extra\_tags) | Extra tags for Cronjob monitor | `list(string)` | `[]` | no | +| [cronjob\_message](#input\_cronjob\_message) | Custom message for Cronjob monitor | `string` | `""` | no | +| [cronjob\_threshold\_warning](#input\_cronjob\_threshold\_warning) | Cronjob monitor (warning threshold) | `string` | `3` | no | +| [environment](#input\_environment) | Architecture environment | `any` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [job\_enabled](#input\_job\_enabled) | Flag to enable Job monitor | `string` | `"true"` | no | +| [job\_extra\_tags](#input\_job\_extra\_tags) | Extra tags for Job monitor | `list(string)` | `[]` | no | +| [job\_message](#input\_job\_message) | Custom message for Job monitor | `string` | `""` | no | +| [job\_threshold\_warning](#input\_job\_threshold\_warning) | Job monitor (warning threshold) | `string` | `3` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [replica\_available\_enabled](#input\_replica\_available\_enabled) | Flag to enable Available replica monitor | `string` | `"true"` | no | +| [replica\_available\_extra\_tags](#input\_replica\_available\_extra\_tags) | Extra tags for Available replicamonitor | `list(string)` | `[]` | no | +| [replica\_available\_message](#input\_replica\_available\_message) | Custom message for Available replica monitor | `string` | `""` | no | +| [replica\_available\_threshold\_critical](#input\_replica\_available\_threshold\_critical) | Available replica critical threshold | `number` | `1` | no | +| [replica\_available\_time\_aggregator](#input\_replica\_available\_time\_aggregator) | Monitor aggregator for Available replica [available values: min, max or avg] | `string` | `"max"` | no | +| [replica\_available\_timeframe](#input\_replica\_available\_timeframe) | Monitor timeframe for Available replica [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [replica\_current\_enabled](#input\_replica\_current\_enabled) | Flag to enable Current replica monitor | `string` | `"true"` | no | +| [replica\_current\_extra\_tags](#input\_replica\_current\_extra\_tags) | Extra tags for Current replica monitor | `list(string)` | `[]` | no | +| [replica\_current\_message](#input\_replica\_current\_message) | Custom message for Current replica monitor | `string` | `""` | no | +| [replica\_current\_threshold\_critical](#input\_replica\_current\_threshold\_critical) | Current replica critical threshold | `number` | `1` | no | +| [replica\_current\_time\_aggregator](#input\_replica\_current\_time\_aggregator) | Monitor aggregator for Current replica [available values: min, max or avg] | `string` | `"max"` | no | +| [replica\_current\_timeframe](#input\_replica\_current\_timeframe) | Monitor timeframe for Current replica [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [replica\_ready\_enabled](#input\_replica\_ready\_enabled) | Flag to enable Ready replica monitor | `string` | `"true"` | no | +| [replica\_ready\_extra\_tags](#input\_replica\_ready\_extra\_tags) | Extra tags for Ready replica monitor | `list(string)` | `[]` | no | +| [replica\_ready\_message](#input\_replica\_ready\_message) | Custom message for Ready replica monitor | `string` | `""` | no | +| [replica\_ready\_threshold\_critical](#input\_replica\_ready\_threshold\_critical) | Ready replica critical threshold | `number` | `1` | no | +| [replica\_ready\_time\_aggregator](#input\_replica\_ready\_time\_aggregator) | Monitor aggregator for Ready replica [available values: min, max or avg] | `string` | `"max"` | no | +| [replica\_ready\_timeframe](#input\_replica\_ready\_timeframe) | Monitor timeframe for Ready replica [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cronjob\_id](#output\_cronjob\_id) | id for monitor cronjob | +| [job\_id](#output\_job\_id) | id for monitor job | +| [replica\_available\_id](#output\_replica\_available\_id) | id for monitor replica\_available | +| [replica\_current\_id](#output\_replica\_current\_id) | id for monitor replica\_current | +| [replica\_ready\_id](#output\_replica\_ready\_id) | id for monitor replica\_ready | +## Related documentation + +* [Datadog metrics](https://docs.datadoghq.com/agent/kubernetes/metrics/) +* [Datadog documentation](https://docs.datadoghq.com/integrations/kubernetes/) +* [Datadog Blog](https://www.datadoghq.com/blog/monitor-kubernetes-docker/) + +## Requirements + +* Datadog Agent > v6.6 diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/workload/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/workload/inputs.tf new file mode 100755 index 0000000..6c44b2b --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/workload/inputs.tf @@ -0,0 +1,200 @@ +# Datadog global variables + +variable "environment" { + description = "Architecture environment" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# Datadog monitors variables + +variable "job_enabled" { + description = "Flag to enable Job monitor" + type = string + default = "true" +} + +variable "job_extra_tags" { + description = "Extra tags for Job monitor" + type = list(string) + default = [] +} + +variable "job_message" { + description = "Custom message for Job monitor" + type = string + default = "" +} + +variable "job_threshold_warning" { + description = "Job monitor (warning threshold)" + type = string + default = 3 +} + +variable "cronjob_enabled" { + description = "Flag to enable Cronjob monitor" + type = string + default = "true" +} + +variable "cronjob_extra_tags" { + description = "Extra tags for Cronjob monitor" + type = list(string) + default = [] +} + +variable "cronjob_message" { + description = "Custom message for Cronjob monitor" + type = string + default = "" +} + +variable "cronjob_threshold_warning" { + description = "Cronjob monitor (warning threshold)" + type = string + default = 3 +} + +variable "replica_available_enabled" { + description = "Flag to enable Available replica monitor" + type = string + default = "true" +} + +variable "replica_available_extra_tags" { + description = "Extra tags for Available replicamonitor" + type = list(string) + default = [] +} + +variable "replica_available_message" { + description = "Custom message for Available replica monitor" + type = string + default = "" +} + +variable "replica_available_time_aggregator" { + description = "Monitor aggregator for Available replica [available values: min, max or avg]" + type = string + default = "max" +} + +variable "replica_available_timeframe" { + description = "Monitor timeframe for Available replica [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "replica_available_threshold_critical" { + default = 1 + description = "Available replica critical threshold" +} + +variable "replica_ready_enabled" { + description = "Flag to enable Ready replica monitor" + type = string + default = "true" +} + +variable "replica_ready_extra_tags" { + description = "Extra tags for Ready replica monitor" + type = list(string) + default = [] +} + +variable "replica_ready_message" { + description = "Custom message for Ready replica monitor" + type = string + default = "" +} + +variable "replica_ready_time_aggregator" { + description = "Monitor aggregator for Ready replica [available values: min, max or avg]" + type = string + default = "max" +} + +variable "replica_ready_timeframe" { + description = "Monitor timeframe for Ready replica [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "replica_ready_threshold_critical" { + default = 1 + description = "Ready replica critical threshold" +} + +variable "replica_current_enabled" { + description = "Flag to enable Current replica monitor" + type = string + default = "true" +} + +variable "replica_current_extra_tags" { + description = "Extra tags for Current replica monitor" + type = list(string) + default = [] +} + +variable "replica_current_message" { + description = "Custom message for Current replica monitor" + type = string + default = "" +} + +variable "replica_current_time_aggregator" { + description = "Monitor aggregator for Current replica [available values: min, max or avg]" + type = string + default = "max" +} + +variable "replica_current_timeframe" { + description = "Monitor timeframe for Current replica [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "replica_current_threshold_critical" { + default = 1 + description = "Current replica critical threshold" +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/workload/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/workload/modules.tf new file mode 100755 index 0000000..a57cf43 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/workload/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "kubernetes" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/workload/monitors-k8s-workload.tf b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/workload/monitors-k8s-workload.tf new file mode 100755 index 0000000..41ebbb4 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/caas/kubernetes/workload/monitors-k8s-workload.tf @@ -0,0 +1,144 @@ +resource "datadog_monitor" "job" { + count = var.job_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Kubernetes job failed" + message = coalesce(var.job_message, var.message) + type = "service check" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.ALB_httpcode_4xx](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ALB_httpcode_5xx](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ALB_httpcode_target_4xx](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ALB_httpcode_target_5xx](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ALB_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ALB_no_healthy_instances](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [alb\_no\_healthy\_instances\_enabled](#input\_alb\_no\_healthy\_instances\_enabled) | Flag to enable ALB no healthy instances monitor | `string` | `"true"` | no | +| [alb\_no\_healthy\_instances\_extra\_tags](#input\_alb\_no\_healthy\_instances\_extra\_tags) | Extra tags for ALB no healthy instances monitor | `list(string)` | `[]` | no | +| [alb\_no\_healthy\_instances\_message](#input\_alb\_no\_healthy\_instances\_message) | Custom message for ALB no healthy instances monitor | `string` | `""` | no | +| [alb\_no\_healthy\_instances\_no\_data\_timeframe](#input\_alb\_no\_healthy\_instances\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [alb\_no\_healthy\_instances\_threshold\_warning](#input\_alb\_no\_healthy\_instances\_threshold\_warning) | ALB no healthy instances warning threshold in percentage | `number` | `100` | no | +| [alb\_no\_healthy\_instances\_time\_aggregator](#input\_alb\_no\_healthy\_instances\_time\_aggregator) | Monitor aggregator for ALB no healthy instances [available values: min, max or avg] | `string` | `"min"` | no | +| [alb\_no\_healthy\_instances\_timeframe](#input\_alb\_no\_healthy\_instances\_timeframe) | Monitor timeframe for ALB no healthy instances [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [artificial\_requests\_count](#input\_artificial\_requests\_count) | Number of false requests used to mitigate false positive in case of low trafic | `number` | `5` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [httpcode\_alb\_4xx\_enabled](#input\_httpcode\_alb\_4xx\_enabled) | Flag to enable ALB httpcode 4xx monitor | `string` | `"true"` | no | +| [httpcode\_alb\_4xx\_extra\_tags](#input\_httpcode\_alb\_4xx\_extra\_tags) | Extra tags for ALB httpcode 4xx monitor | `list(string)` | `[]` | no | +| [httpcode\_alb\_4xx\_message](#input\_httpcode\_alb\_4xx\_message) | Custom message for ALB httpcode 4xx monitor | `string` | `""` | no | +| [httpcode\_alb\_4xx\_threshold\_critical](#input\_httpcode\_alb\_4xx\_threshold\_critical) | loadbalancer 4xx critical threshold in percentage | `number` | `80` | no | +| [httpcode\_alb\_4xx\_threshold\_warning](#input\_httpcode\_alb\_4xx\_threshold\_warning) | loadbalancer 4xx warning threshold in percentage | `number` | `60` | no | +| [httpcode\_alb\_4xx\_time\_aggregator](#input\_httpcode\_alb\_4xx\_time\_aggregator) | Monitor aggregator for ALB httpcode 4xx [available values: min, max or avg] | `string` | `"min"` | no | +| [httpcode\_alb\_4xx\_timeframe](#input\_httpcode\_alb\_4xx\_timeframe) | Monitor timeframe for ALB httpcode 4xx [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [httpcode\_alb\_5xx\_enabled](#input\_httpcode\_alb\_5xx\_enabled) | Flag to enable ALB httpcode 5xx monitor | `string` | `"true"` | no | +| [httpcode\_alb\_5xx\_extra\_tags](#input\_httpcode\_alb\_5xx\_extra\_tags) | Extra tags for ALB httpcode 5xx monitor | `list(string)` | `[]` | no | +| [httpcode\_alb\_5xx\_message](#input\_httpcode\_alb\_5xx\_message) | Custom message for ALB httpcode 5xx monitor | `string` | `""` | no | +| [httpcode\_alb\_5xx\_threshold\_critical](#input\_httpcode\_alb\_5xx\_threshold\_critical) | loadbalancer 5xx critical threshold in percentage | `number` | `80` | no | +| [httpcode\_alb\_5xx\_threshold\_warning](#input\_httpcode\_alb\_5xx\_threshold\_warning) | loadbalancer 5xx warning threshold in percentage | `number` | `60` | no | +| [httpcode\_alb\_5xx\_time\_aggregator](#input\_httpcode\_alb\_5xx\_time\_aggregator) | Monitor aggregator for ALB httpcode 5xx [available values: min, max or avg] | `string` | `"min"` | no | +| [httpcode\_alb\_5xx\_timeframe](#input\_httpcode\_alb\_5xx\_timeframe) | Monitor timeframe for ALB httpcode 5xx [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [httpcode\_target\_4xx\_enabled](#input\_httpcode\_target\_4xx\_enabled) | Flag to enable ALB target httpcode 4xx monitor | `string` | `"true"` | no | +| [httpcode\_target\_4xx\_extra\_tags](#input\_httpcode\_target\_4xx\_extra\_tags) | Extra tags for ALB target httpcode 4xx monitor | `list(string)` | `[]` | no | +| [httpcode\_target\_4xx\_message](#input\_httpcode\_target\_4xx\_message) | Custom message for ALB target httpcode 4xx monitor | `string` | `""` | no | +| [httpcode\_target\_4xx\_threshold\_critical](#input\_httpcode\_target\_4xx\_threshold\_critical) | target 4xx critical threshold in percentage | `number` | `80` | no | +| [httpcode\_target\_4xx\_threshold\_warning](#input\_httpcode\_target\_4xx\_threshold\_warning) | target 4xx warning threshold in percentage | `number` | `60` | no | +| [httpcode\_target\_4xx\_time\_aggregator](#input\_httpcode\_target\_4xx\_time\_aggregator) | Monitor aggregator for ALB target httpcode 4xx [available values: min, max or avg] | `string` | `"min"` | no | +| [httpcode\_target\_4xx\_timeframe](#input\_httpcode\_target\_4xx\_timeframe) | Monitor timeframe for ALB target httpcode 4xx [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [httpcode\_target\_5xx\_enabled](#input\_httpcode\_target\_5xx\_enabled) | Flag to enable ALB target httpcode 5xx monitor | `string` | `"true"` | no | +| [httpcode\_target\_5xx\_extra\_tags](#input\_httpcode\_target\_5xx\_extra\_tags) | Extra tags for ALB target httpcode 5xx monitor | `list(string)` | `[]` | no | +| [httpcode\_target\_5xx\_message](#input\_httpcode\_target\_5xx\_message) | Custom message for ALB target httpcode 5xx monitor | `string` | `""` | no | +| [httpcode\_target\_5xx\_threshold\_critical](#input\_httpcode\_target\_5xx\_threshold\_critical) | target 5xx critical threshold in percentage | `number` | `80` | no | +| [httpcode\_target\_5xx\_threshold\_warning](#input\_httpcode\_target\_5xx\_threshold\_warning) | target 5xx warning threshold in percentage | `number` | `60` | no | +| [httpcode\_target\_5xx\_time\_aggregator](#input\_httpcode\_target\_5xx\_time\_aggregator) | Monitor aggregator for ALB target httpcode 5xx [available values: min, max or avg] | `string` | `"min"` | no | +| [httpcode\_target\_5xx\_timeframe](#input\_httpcode\_target\_5xx\_timeframe) | Monitor timeframe for ALB target httpcode 5xx [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [latency\_enabled](#input\_latency\_enabled) | Flag to enable ALB latency monitor | `string` | `"true"` | no | +| [latency\_extra\_tags](#input\_latency\_extra\_tags) | Extra tags for ALB latency monitor | `list(string)` | `[]` | no | +| [latency\_message](#input\_latency\_message) | Custom message for ALB latency monitor | `string` | `""` | no | +| [latency\_threshold\_critical](#input\_latency\_threshold\_critical) | latency critical threshold in seconds | `number` | `3` | no | +| [latency\_threshold\_warning](#input\_latency\_threshold\_warning) | latency warning threshold in seconds | `number` | `1` | no | +| [latency\_time\_aggregator](#input\_latency\_time\_aggregator) | Monitor aggregator for ALB latency [available values: min, max or avg] | `string` | `"min"` | no | +| [latency\_timeframe](#input\_latency\_timeframe) | Monitor timeframe for ALB latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [ALB\_httpcode\_4xx\_id](#output\_ALB\_httpcode\_4xx\_id) | id for monitor ALB\_httpcode\_4xx | +| [ALB\_httpcode\_5xx\_id](#output\_ALB\_httpcode\_5xx\_id) | id for monitor ALB\_httpcode\_5xx | +| [ALB\_httpcode\_target\_4xx\_id](#output\_ALB\_httpcode\_target\_4xx\_id) | id for monitor ALB\_httpcode\_target\_4xx | +| [ALB\_httpcode\_target\_5xx\_id](#output\_ALB\_httpcode\_target\_5xx\_id) | id for monitor ALB\_httpcode\_target\_5xx | +| [ALB\_latency\_id](#output\_ALB\_latency\_id) | id for monitor ALB\_latency | +| [ALB\_no\_healthy\_instances\_id](#output\_ALB\_no\_healthy\_instances\_id) | id for monitor ALB\_no\_healthy\_instances | +## Related documentation + +DataDog blog: [https://www.datadoghq.com/blog/monitor-application-load-balancer/](https://www.datadoghq.com/blog/monitor-application-load-balancer/) + +AWS ALB metrics documentation: [https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-cloudwatch-metrics.html](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-cloudwatch-metrics.html) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/alb/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/alb/inputs.tf new file mode 100755 index 0000000..e175bef --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/alb/inputs.tf @@ -0,0 +1,294 @@ +# Datadog global variables + +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "alb_no_healthy_instances_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# Datadog monitors variables + +variable "alb_no_healthy_instances_enabled" { + description = "Flag to enable ALB no healthy instances monitor" + type = string + default = "true" +} + +variable "alb_no_healthy_instances_extra_tags" { + description = "Extra tags for ALB no healthy instances monitor" + type = list(string) + default = [] +} + +variable "alb_no_healthy_instances_message" { + description = "Custom message for ALB no healthy instances monitor" + type = string + default = "" +} + +variable "alb_no_healthy_instances_time_aggregator" { + description = "Monitor aggregator for ALB no healthy instances [available values: min, max or avg]" + type = string + default = "min" +} + +variable "alb_no_healthy_instances_timeframe" { + description = "Monitor timeframe for ALB no healthy instances [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "alb_no_healthy_instances_threshold_warning" { + description = "ALB no healthy instances warning threshold in percentage" + default = 100 +} + +variable "latency_enabled" { + description = "Flag to enable ALB latency monitor" + type = string + default = "true" +} + +variable "latency_extra_tags" { + description = "Extra tags for ALB latency monitor" + type = list(string) + default = [] +} + +variable "latency_message" { + description = "Custom message for ALB latency monitor" + type = string + default = "" +} + +variable "latency_time_aggregator" { + description = "Monitor aggregator for ALB latency [available values: min, max or avg]" + type = string + default = "min" +} + +variable "latency_timeframe" { + description = "Monitor timeframe for ALB latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "latency_threshold_critical" { + default = 3 + description = "latency critical threshold in seconds" +} + +variable "latency_threshold_warning" { + default = 1 + description = "latency warning threshold in seconds" +} + +variable "httpcode_alb_4xx_enabled" { + description = "Flag to enable ALB httpcode 4xx monitor" + type = string + default = "true" +} + +variable "httpcode_alb_4xx_extra_tags" { + description = "Extra tags for ALB httpcode 4xx monitor" + type = list(string) + default = [] +} + +variable "httpcode_alb_4xx_message" { + description = "Custom message for ALB httpcode 4xx monitor" + type = string + default = "" +} + +variable "httpcode_alb_4xx_time_aggregator" { + description = "Monitor aggregator for ALB httpcode 4xx [available values: min, max or avg]" + type = string + default = "min" +} + +variable "httpcode_alb_4xx_timeframe" { + description = "Monitor timeframe for ALB httpcode 4xx [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "httpcode_alb_4xx_threshold_critical" { + default = 80 + description = "loadbalancer 4xx critical threshold in percentage" +} + +variable "httpcode_alb_4xx_threshold_warning" { + default = 60 + description = "loadbalancer 4xx warning threshold in percentage" +} + +variable "httpcode_target_4xx_enabled" { + description = "Flag to enable ALB target httpcode 4xx monitor" + type = string + default = "true" +} + +variable "httpcode_target_4xx_extra_tags" { + description = "Extra tags for ALB target httpcode 4xx monitor" + type = list(string) + default = [] +} + +variable "httpcode_target_4xx_message" { + description = "Custom message for ALB target httpcode 4xx monitor" + type = string + default = "" +} + +variable "httpcode_target_4xx_time_aggregator" { + description = "Monitor aggregator for ALB target httpcode 4xx [available values: min, max or avg]" + type = string + default = "min" +} + +variable "httpcode_target_4xx_timeframe" { + description = "Monitor timeframe for ALB target httpcode 4xx [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "httpcode_target_4xx_threshold_critical" { + default = 80 + description = "target 4xx critical threshold in percentage" +} + +variable "httpcode_target_4xx_threshold_warning" { + default = 60 + description = "target 4xx warning threshold in percentage" +} + +variable "httpcode_alb_5xx_enabled" { + description = "Flag to enable ALB httpcode 5xx monitor" + type = string + default = "true" +} + +variable "httpcode_alb_5xx_extra_tags" { + description = "Extra tags for ALB httpcode 5xx monitor" + type = list(string) + default = [] +} + +variable "httpcode_alb_5xx_message" { + description = "Custom message for ALB httpcode 5xx monitor" + type = string + default = "" +} + +variable "httpcode_alb_5xx_time_aggregator" { + description = "Monitor aggregator for ALB httpcode 5xx [available values: min, max or avg]" + type = string + default = "min" +} + +variable "httpcode_alb_5xx_timeframe" { + description = "Monitor timeframe for ALB httpcode 5xx [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "httpcode_alb_5xx_threshold_critical" { + default = 80 + description = "loadbalancer 5xx critical threshold in percentage" +} + +variable "httpcode_alb_5xx_threshold_warning" { + default = 60 + description = "loadbalancer 5xx warning threshold in percentage" +} + +variable "httpcode_target_5xx_enabled" { + description = "Flag to enable ALB target httpcode 5xx monitor" + type = string + default = "true" +} + +variable "httpcode_target_5xx_extra_tags" { + description = "Extra tags for ALB target httpcode 5xx monitor" + type = list(string) + default = [] +} + +variable "httpcode_target_5xx_message" { + description = "Custom message for ALB target httpcode 5xx monitor" + type = string + default = "" +} + +variable "httpcode_target_5xx_time_aggregator" { + description = "Monitor aggregator for ALB target httpcode 5xx [available values: min, max or avg]" + type = string + default = "min" +} + +variable "httpcode_target_5xx_timeframe" { + description = "Monitor timeframe for ALB target httpcode 5xx [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "httpcode_target_5xx_threshold_critical" { + default = 80 + description = "target 5xx critical threshold in percentage" +} + +variable "httpcode_target_5xx_threshold_warning" { + default = 60 + description = "target 5xx warning threshold in percentage" +} + +variable "artificial_requests_count" { + default = 5 + description = "Number of false requests used to mitigate false positive in case of low trafic" +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/alb/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/alb/modules.tf new file mode 100755 index 0000000..480c3d6 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/alb/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "aws_alb" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/alb/monitors-alb.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/alb/monitors-alb.tf new file mode 100755 index 0000000..36f4b8d --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/alb/monitors-alb.tf @@ -0,0 +1,175 @@ +resource "datadog_monitor" "ALB_no_healthy_instances" { + count = var.alb_no_healthy_instances_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ALB healthy instances {{#is_alert}}is at 0{{/is_alert}}{{#is_warning}}is at {{value}}%%{{/is_warning}}" + message = coalesce(var.alb_no_healthy_instances_message, var.message) + type = "query alert" + + query = < ${var.latency_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.latency_threshold_critical + warning = var.latency_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:alb", "team:claranet", "created-by:terraform"], var.latency_extra_tags) +} + +resource "datadog_monitor" "ALB_httpcode_5xx" { + count = var.httpcode_alb_5xx_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ALB HTTP code 5xx {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.httpcode_alb_5xx_message, var.message) + type = "query alert" + + query = < ${var.httpcode_alb_5xx_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.httpcode_alb_5xx_threshold_critical + warning = var.httpcode_alb_5xx_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:alb", "team:claranet", "created-by:terraform"], var.httpcode_alb_5xx_extra_tags) +} + +resource "datadog_monitor" "ALB_httpcode_4xx" { + count = var.httpcode_alb_4xx_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ALB HTTP code 4xx {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.httpcode_alb_4xx_message, var.message) + type = "query alert" + + query = < ${var.httpcode_alb_4xx_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.httpcode_alb_4xx_threshold_critical + warning = var.httpcode_alb_4xx_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:alb", "team:claranet", "created-by:terraform"], var.httpcode_alb_4xx_extra_tags) +} + +resource "datadog_monitor" "ALB_httpcode_target_5xx" { + count = var.httpcode_target_5xx_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ALB target HTTP code 5xx {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.httpcode_target_5xx_message, var.message) + type = "query alert" + + query = < ${var.httpcode_target_5xx_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.httpcode_target_5xx_threshold_critical + warning = var.httpcode_target_5xx_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:alb", "team:claranet", "created-by:terraform"], var.httpcode_target_5xx_extra_tags) +} + +resource "datadog_monitor" "ALB_httpcode_target_4xx" { + count = var.httpcode_target_4xx_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ALB target HTTP code 4xx {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.httpcode_target_4xx_message, var.message) + type = "query alert" + + query = < ${var.httpcode_target_4xx_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.httpcode_target_4xx_threshold_critical + warning = var.httpcode_target_4xx_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:alb", "team:claranet", "created-by:terraform"], var.httpcode_target_4xx_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/alb/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/alb/outputs.tf new file mode 100755 index 0000000..f2e72d1 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/alb/outputs.tf @@ -0,0 +1,30 @@ +output "ALB_httpcode_4xx_id" { + description = "id for monitor ALB_httpcode_4xx" + value = datadog_monitor.ALB_httpcode_4xx.*.id +} + +output "ALB_httpcode_5xx_id" { + description = "id for monitor ALB_httpcode_5xx" + value = datadog_monitor.ALB_httpcode_5xx.*.id +} + +output "ALB_httpcode_target_4xx_id" { + description = "id for monitor ALB_httpcode_target_4xx" + value = datadog_monitor.ALB_httpcode_target_4xx.*.id +} + +output "ALB_httpcode_target_5xx_id" { + description = "id for monitor ALB_httpcode_target_5xx" + value = datadog_monitor.ALB_httpcode_target_5xx.*.id +} + +output "ALB_latency_id" { + description = "id for monitor ALB_latency" + value = datadog_monitor.ALB_latency.*.id +} + +output "ALB_no_healthy_instances_id" { + description = "id for monitor ALB_no_healthy_instances" + value = datadog_monitor.ALB_no_healthy_instances.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/alb/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/alb/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/alb/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/apigateway/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/apigateway/README.md new file mode 100755 index 0000000..a080e78 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/apigateway/README.md @@ -0,0 +1,94 @@ +# CLOUD AWS APIGATEWAY DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-apigateway" { + source = "claranet/monitors/datadog//cloud/aws/apigateway" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- API Gateway HTTP 4xx errors +- API Gateway HTTP 5xx errors +- API Gateway latency + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.API_Gateway_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.API_http_4xx_errors_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.API_http_5xx_errors_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [artificial\_requests\_count](#input\_artificial\_requests\_count) | Number of false requests used to mitigate false positive in case of low trafic | `number` | `5` | no | +| [environment](#input\_environment) | Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags](#input\_filter\_tags) | Tags used for filtering | `string` | `"*"` | no | +| [http\_4xx\_requests\_enabled](#input\_http\_4xx\_requests\_enabled) | Flag to enable API Gateway HTTP 4xx requests monitor | `string` | `"true"` | no | +| [http\_4xx\_requests\_extra\_tags](#input\_http\_4xx\_requests\_extra\_tags) | Extra tags for API Gateway HTTP 4xx requests monitor | `list(string)` | `[]` | no | +| [http\_4xx\_requests\_message](#input\_http\_4xx\_requests\_message) | Custom message for API Gateway HTTP 4xx requests monitor | `string` | `""` | no | +| [http\_4xx\_requests\_threshold\_critical](#input\_http\_4xx\_requests\_threshold\_critical) | Maximum critical acceptable percent of 4xx errors | `number` | `30` | no | +| [http\_4xx\_requests\_threshold\_warning](#input\_http\_4xx\_requests\_threshold\_warning) | Maximum warning acceptable percent of 4xx errors | `number` | `15` | no | +| [http\_4xx\_requests\_time\_aggregator](#input\_http\_4xx\_requests\_time\_aggregator) | Monitor aggregator for API HTTP 4xx requests [available values: min, max or avg] | `string` | `"min"` | no | +| [http\_4xx\_requests\_timeframe](#input\_http\_4xx\_requests\_timeframe) | Monitor timeframe for API HTTP 4xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [http\_5xx\_requests\_enabled](#input\_http\_5xx\_requests\_enabled) | Flag to enable API Gateway HTTP 5xx requests monitor | `string` | `"true"` | no | +| [http\_5xx\_requests\_extra\_tags](#input\_http\_5xx\_requests\_extra\_tags) | Extra tags for API Gateway HTTP 5xx requests monitor | `list(string)` | `[]` | no | +| [http\_5xx\_requests\_message](#input\_http\_5xx\_requests\_message) | Custom message for API Gateway HTTP 5xx requests monitor | `string` | `""` | no | +| [http\_5xx\_requests\_threshold\_critical](#input\_http\_5xx\_requests\_threshold\_critical) | Maximum critical acceptable percent of 5xx errors | `number` | `20` | no | +| [http\_5xx\_requests\_threshold\_warning](#input\_http\_5xx\_requests\_threshold\_warning) | Maximum warning acceptable percent of 5xx errors | `number` | `10` | no | +| [http\_5xx\_requests\_time\_aggregator](#input\_http\_5xx\_requests\_time\_aggregator) | Monitor aggregator for API HTTP 5xx requests [available values: min, max or avg] | `string` | `"min"` | no | +| [http\_5xx\_requests\_timeframe](#input\_http\_5xx\_requests\_timeframe) | Monitor timeframe for API HTTP 5xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [latency\_enabled](#input\_latency\_enabled) | Flag to enable API Gateway latency monitor | `string` | `"true"` | no | +| [latency\_extra\_tags](#input\_latency\_extra\_tags) | Extra tags for API Gateway latency monitor | `list(string)` | `[]` | no | +| [latency\_message](#input\_latency\_message) | Custom message for API Gateway latency monitor | `string` | `""` | no | +| [latency\_threshold\_critical](#input\_latency\_threshold\_critical) | Alerting threshold in milliseconds | `number` | `3000` | no | +| [latency\_threshold\_warning](#input\_latency\_threshold\_warning) | Warning threshold in milliseconds | `number` | `1000` | no | +| [latency\_time\_aggregator](#input\_latency\_time\_aggregator) | Monitor aggregator for API Gateway latency [available values: min, max or avg] | `string` | `"min"` | no | +| [latency\_timeframe](#input\_latency\_timeframe) | Monitor timeframe for API latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [API\_Gateway\_latency\_id](#output\_API\_Gateway\_latency\_id) | id for monitor API\_Gateway\_latency | +| [API\_http\_4xx\_errors\_count\_id](#output\_API\_http\_4xx\_errors\_count\_id) | id for monitor API\_http\_4xx\_errors\_count | +| [API\_http\_5xx\_errors\_count\_id](#output\_API\_http\_5xx\_errors\_count\_id) | id for monitor API\_http\_5xx\_errors\_count | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/amazon_api_gateway/](https://docs.datadoghq.com/integrations/amazon_api_gateway/) + +AWS API Gateway metrics documentation: [https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/api-gateway-metrics-dimensions.html](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/api-gateway-metrics-dimensions.html) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/apigateway/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/apigateway/inputs.tf new file mode 100755 index 0000000..174bc15 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/apigateway/inputs.tf @@ -0,0 +1,171 @@ +variable "environment" { + description = "Environment" + type = string +} + +variable "filter_tags" { + description = "Tags used for filtering" + default = "*" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +################################### +### LATENCY VARIABLES ### +################################### + +variable "latency_enabled" { + description = "Flag to enable API Gateway latency monitor" + type = string + default = "true" +} + +variable "latency_extra_tags" { + description = "Extra tags for API Gateway latency monitor" + type = list(string) + default = [] +} + +variable "latency_message" { + description = "Custom message for API Gateway latency monitor" + type = string + default = "" +} + +variable "latency_time_aggregator" { + description = "Monitor aggregator for API Gateway latency [available values: min, max or avg]" + type = string + default = "min" +} + +variable "latency_timeframe" { + description = "Monitor timeframe for API latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "latency_threshold_critical" { + default = 3000 + description = "Alerting threshold in milliseconds" +} + +variable "latency_threshold_warning" { + default = 1000 + description = "Warning threshold in milliseconds" +} + +################################# +### HTTP 5xx status pages ### +################################# + +variable "http_5xx_requests_enabled" { + description = "Flag to enable API Gateway HTTP 5xx requests monitor" + type = string + default = "true" +} + +variable "http_5xx_requests_extra_tags" { + description = "Extra tags for API Gateway HTTP 5xx requests monitor" + type = list(string) + default = [] +} + +variable "http_5xx_requests_message" { + description = "Custom message for API Gateway HTTP 5xx requests monitor" + type = string + default = "" +} + +variable "http_5xx_requests_time_aggregator" { + description = "Monitor aggregator for API HTTP 5xx requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "http_5xx_requests_timeframe" { + description = "Monitor timeframe for API HTTP 5xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "http_5xx_requests_threshold_critical" { + default = 20 + description = "Maximum critical acceptable percent of 5xx errors" +} + +variable "http_5xx_requests_threshold_warning" { + default = 10 + description = "Maximum warning acceptable percent of 5xx errors" +} + +################################# +### HTTP 4xx status pages ### +################################# + +variable "http_4xx_requests_enabled" { + description = "Flag to enable API Gateway HTTP 4xx requests monitor" + type = string + default = "true" +} + +variable "http_4xx_requests_extra_tags" { + description = "Extra tags for API Gateway HTTP 4xx requests monitor" + type = list(string) + default = [] +} + +variable "http_4xx_requests_message" { + description = "Custom message for API Gateway HTTP 4xx requests monitor" + type = string + default = "" +} + +variable "http_4xx_requests_time_aggregator" { + description = "Monitor aggregator for API HTTP 4xx requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "http_4xx_requests_timeframe" { + description = "Monitor timeframe for API HTTP 4xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "http_4xx_requests_threshold_critical" { + default = 30 + description = "Maximum critical acceptable percent of 4xx errors" +} + +variable "http_4xx_requests_threshold_warning" { + default = 15 + description = "Maximum warning acceptable percent of 4xx errors" +} + +variable "artificial_requests_count" { + default = 5 + description = "Number of false requests used to mitigate false positive in case of low trafic" +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/apigateway/monitors-api.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/apigateway/monitors-api.tf new file mode 100755 index 0000000..18bfa8f --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/apigateway/monitors-api.tf @@ -0,0 +1,89 @@ +# Monitoring Api Gateway latency +resource "datadog_monitor" "API_Gateway_latency" { + count = var.latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] API Gateway latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.latency_message, var.message) + type = "query alert" + + query = < ${var.latency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.latency_threshold_warning + critical = var.latency_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:apigateway", "team:claranet", "created-by:terraform"], var.latency_extra_tags) +} + +# Monitoring API Gateway 5xx errors percent +resource "datadog_monitor" "API_http_5xx_errors_count" { + count = var.http_5xx_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] API Gateway HTTP 5xx errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.http_5xx_requests_message, var.message) + type = "query alert" + + query = < ${var.http_5xx_requests_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.http_5xx_requests_threshold_warning + critical = var.http_5xx_requests_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 1 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:apigateway", "team:claranet", "created-by:terraform"], var.http_5xx_requests_extra_tags) +} + +# Monitoring API Gateway 4xx errors percent +resource "datadog_monitor" "API_http_4xx_errors_count" { + count = var.http_4xx_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] API Gateway HTTP 4xx errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.http_4xx_requests_message, var.message) + type = "query alert" + + query = < ${var.http_4xx_requests_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.http_4xx_requests_threshold_warning + critical = var.http_4xx_requests_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 1 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:apigateway", "team:claranet", "created-by:terraform"], var.http_4xx_requests_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/apigateway/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/apigateway/outputs.tf new file mode 100755 index 0000000..9c411dc --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/apigateway/outputs.tf @@ -0,0 +1,15 @@ +output "API_Gateway_latency_id" { + description = "id for monitor API_Gateway_latency" + value = datadog_monitor.API_Gateway_latency.*.id +} + +output "API_http_4xx_errors_count_id" { + description = "id for monitor API_http_4xx_errors_count" + value = datadog_monitor.API_http_4xx_errors_count.*.id +} + +output "API_http_5xx_errors_count_id" { + description = "id for monitor API_http_5xx_errors_count" + value = datadog_monitor.API_http_5xx_errors_count.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/apigateway/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/apigateway/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/apigateway/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/beanstalk/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/beanstalk/README.md new file mode 100755 index 0000000..7239061 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/beanstalk/README.md @@ -0,0 +1,110 @@ +# CLOUD AWS BEANSTALK DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-beanstalk" { + source = "claranet/monitors/datadog//cloud/aws/beanstalk" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Beanstalk Application 5xx error rate +- Beanstalk Application latency p90 +- Beanstalk Environment health +- Beanstalk Instance root file system usage + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | +| [filter-tags-no-host](#module\_filter-tags-no-host) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.application_5xx_error_rate](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.application_latency_p90](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.health](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.root_filesystem_usage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [application\_5xx\_error\_rate\_enabled](#input\_application\_5xx\_error\_rate\_enabled) | Flag to enable Beanstalk application 5xx error ratemonitor | `string` | `"true"` | no | +| [application\_5xx\_error\_rate\_extra\_tags](#input\_application\_5xx\_error\_rate\_extra\_tags) | Extra tags for application 5xx error rate monitor | `list(string)` | `[]` | no | +| [application\_5xx\_error\_rate\_message](#input\_application\_5xx\_error\_rate\_message) | Custom message for application 5xx error rate | `string` | `""` | no | +| [application\_5xx\_error\_rate\_threshold\_critical](#input\_application\_5xx\_error\_rate\_threshold\_critical) | 5xx Error rate critical threshold in percent | `number` | `5` | no | +| [application\_5xx\_error\_rate\_threshold\_warning](#input\_application\_5xx\_error\_rate\_threshold\_warning) | 5xx Error rate warning threshold in percent | `string` | `3` | no | +| [application\_5xx\_error\_rate\_time\_aggregator](#input\_application\_5xx\_error\_rate\_time\_aggregator) | Monitor aggregator for beanstalk application 5xx error rate [available values: min, max or avg] | `string` | `"sum"` | no | +| [application\_5xx\_error\_rate\_timeframe](#input\_application\_5xx\_error\_rate\_timeframe) | Monitor timeframe for beanstalk application 5xx error rate [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [application\_latency\_p90\_enabled](#input\_application\_latency\_p90\_enabled) | Flag to enable Beanstalk application latency P90 monitor | `string` | `"true"` | no | +| [application\_latency\_p90\_extra\_tags](#input\_application\_latency\_p90\_extra\_tags) | Extra tags for application latency P90 monitor | `list(string)` | `[]` | no | +| [application\_latency\_p90\_message](#input\_application\_latency\_p90\_message) | Custom message for application latency P90 monitor | `string` | `""` | no | +| [application\_latency\_p90\_threshold\_critical](#input\_application\_latency\_p90\_threshold\_critical) | P90 Latency critical threshold in seconds | `number` | `0.5` | no | +| [application\_latency\_p90\_threshold\_warning](#input\_application\_latency\_p90\_threshold\_warning) | P90 Latency warning threshold in seconds | `string` | `0.3` | no | +| [application\_latency\_p90\_time\_aggregator](#input\_application\_latency\_p90\_time\_aggregator) | Monitor aggregator for beanstalk application latency P90 [available values: min, max or avg] | `string` | `"min"` | no | +| [application\_latency\_p90\_timeframe](#input\_application\_latency\_p90\_timeframe) | Monitor timeframe for beanstalk application latency P90 [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [health\_enabled](#input\_health\_enabled) | Flag to enable Beanstalk Health monitor | `string` | `"true"` | no | +| [health\_extra\_tags](#input\_health\_extra\_tags) | Extra tags for health monitor | `list(string)` | `[]` | no | +| [health\_message](#input\_health\_message) | Custom message for health monitor | `string` | `""` | no | +| [health\_no\_data\_timeframe](#input\_health\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `20` | no | +| [health\_threshold\_critical](#input\_health\_threshold\_critical) | Health critical threshold (see the `aws.elasticbeanstalk.environment_health` values in the Datadog documentation) | `number` | `20` | no | +| [health\_threshold\_warning](#input\_health\_threshold\_warning) | Health critical threshold (see the `aws.elasticbeanstalk.environment_health` values in the Datadog documentation) | `number` | `15` | no | +| [health\_time\_aggregator](#input\_health\_time\_aggregator) | Monitor aggregator for beanstalk health [available values: min, max or avg] | `string` | `"min"` | no | +| [health\_timeframe](#input\_health\_timeframe) | Monitor timeframe for beanstalk health [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_10m"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [root\_filesystem\_usage\_aggregator](#input\_root\_filesystem\_usage\_aggregator) | Monitor aggregator for beanstalk instance file system usage [available values: min, max or avg] | `string` | `"max"` | no | +| [root\_filesystem\_usage\_enabled](#input\_root\_filesystem\_usage\_enabled) | Flag to enable Beanstalk instance file system usage monitor | `string` | `"true"` | no | +| [root\_filesystem\_usage\_extra\_tags](#input\_root\_filesystem\_usage\_extra\_tags) | Extra tags for file system usage monitor | `list(string)` | `[]` | no | +| [root\_filesystem\_usage\_message](#input\_root\_filesystem\_usage\_message) | Custom message for application file system usage | `string` | `""` | no | +| [root\_filesystem\_usage\_threshold\_critical](#input\_root\_filesystem\_usage\_threshold\_critical) | File system usage critical threshold in percent | `string` | `90` | no | +| [root\_filesystem\_usage\_threshold\_warning](#input\_root\_filesystem\_usage\_threshold\_warning) | File system usage warning threshold in percent | `string` | `80` | no | +| [root\_filesystem\_usage\_timeframe](#input\_root\_filesystem\_usage\_timeframe) | Monitor timeframe for beanstalk instance file system usage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [root\_filesystem\_usage\_timeout\_h](#input\_root\_filesystem\_usage\_timeout\_h) | File system usage auto-resolving state (in hours) | `number` | `0` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [application\_5xx\_error\_rate\_id](#output\_application\_5xx\_error\_rate\_id) | id for monitor application\_5xx\_error\_rate | +| [application\_latency\_p90\_id](#output\_application\_latency\_p90\_id) | id for monitor application\_latency\_p90 | +| [health\_id](#output\_health\_id) | id for monitor health | +| [root\_filesystem\_usage\_id](#output\_root\_filesystem\_usage\_id) | id for monitor root\_filesystem\_usage | +## Related documentation + +Datadog documentation: [https://docs.datadoghq.com/integrations/amazon_elasticbeanstalk/](https://docs.datadoghq.com/integrations/amazon_elasticbeanstalk/) + +AWS Beanstalk Environment monitoring : [https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-health.html](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-health.html) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/beanstalk/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/beanstalk/inputs.tf new file mode 100755 index 0000000..fbdf773 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/beanstalk/inputs.tf @@ -0,0 +1,219 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "health_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 20 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# AWS Beanstalk monitor variables + +variable "health_enabled" { + description = "Flag to enable Beanstalk Health monitor" + type = string + default = "true" +} + +variable "health_message" { + description = "Custom message for health monitor" + default = "" +} + +variable "health_time_aggregator" { + description = "Monitor aggregator for beanstalk health [available values: min, max or avg]" + type = string + default = "min" +} + +variable "health_timeframe" { + description = "Monitor timeframe for beanstalk health [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_10m" +} + +variable "health_threshold_critical" { + description = "Health critical threshold (see the `aws.elasticbeanstalk.environment_health` values in the Datadog documentation)" + default = 20 +} + +variable "health_threshold_warning" { + description = "Health critical threshold (see the `aws.elasticbeanstalk.environment_health` values in the Datadog documentation)" + default = 15 +} + +variable "health_extra_tags" { + description = "Extra tags for health monitor" + type = list(string) + default = [] +} + +variable "application_latency_p90_enabled" { + description = "Flag to enable Beanstalk application latency P90 monitor" + type = string + default = "true" +} + +variable "application_latency_p90_message" { + description = "Custom message for application latency P90 monitor" + default = "" +} + +variable "application_latency_p90_time_aggregator" { + description = "Monitor aggregator for beanstalk application latency P90 [available values: min, max or avg]" + type = string + default = "min" +} + +variable "application_latency_p90_timeframe" { + description = "Monitor timeframe for beanstalk application latency P90 [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "application_latency_p90_threshold_critical" { + description = "P90 Latency critical threshold in seconds" + default = 0.5 +} + +variable "application_latency_p90_threshold_warning" { + description = "P90 Latency warning threshold in seconds" + type = string + default = 0.3 +} + +variable "application_latency_p90_extra_tags" { + description = "Extra tags for application latency P90 monitor" + type = list(string) + default = [] +} + +variable "application_5xx_error_rate_enabled" { + description = "Flag to enable Beanstalk application 5xx error ratemonitor" + type = string + default = "true" +} + +variable "application_5xx_error_rate_message" { + description = "Custom message for application 5xx error rate" + default = "" +} + +variable "application_5xx_error_rate_time_aggregator" { + description = "Monitor aggregator for beanstalk application 5xx error rate [available values: min, max or avg]" + type = string + default = "sum" +} + +variable "application_5xx_error_rate_timeframe" { + description = "Monitor timeframe for beanstalk application 5xx error rate [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "application_5xx_error_rate_threshold_critical" { + description = "5xx Error rate critical threshold in percent" + default = 5 +} + +variable "application_5xx_error_rate_threshold_warning" { + description = "5xx Error rate warning threshold in percent" + type = string + default = 3 +} + +variable "application_5xx_error_rate_extra_tags" { + description = "Extra tags for application 5xx error rate monitor" + type = list(string) + default = [] +} + +variable "root_filesystem_usage_enabled" { + description = "Flag to enable Beanstalk instance file system usage monitor" + type = string + default = "true" +} + +variable "root_filesystem_usage_message" { + description = "Custom message for application file system usage" + default = "" +} + +variable "root_filesystem_usage_aggregator" { + description = "Monitor aggregator for beanstalk instance file system usage [available values: min, max or avg]" + type = string + default = "max" +} + +variable "root_filesystem_usage_timeframe" { + description = "Monitor timeframe for beanstalk instance file system usage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "root_filesystem_usage_threshold_critical" { + description = "File system usage critical threshold in percent" + type = string + default = 90 +} + +variable "root_filesystem_usage_threshold_warning" { + description = "File system usage warning threshold in percent" + type = string + default = 80 +} + +variable "root_filesystem_usage_timeout_h" { + description = "File system usage auto-resolving state (in hours)" + default = 0 +} + +variable "root_filesystem_usage_extra_tags" { + description = "Extra tags for file system usage monitor" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/beanstalk/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/beanstalk/modules.tf new file mode 100755 index 0000000..560dd86 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/beanstalk/modules.tf @@ -0,0 +1,34 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "aws_beanstalk" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + +# With AWS beanstalk some metrics are send per host and per beanstalk env. +# This is particularly the case for all the ApplicationLatency metrics and +# the ApplicationRequests (not for the health and the cpu/disk metrics). +# The best way to find this out is to go on the monitoring configuration page +# of your beanstalk environment. +# +# In order to differentiate those metrics we need to do some exclusion to +# to find out which values has been sent for the host and the one sent for +# the environment itself. +# Some automatic tags are added on the instances by AWS, this seems to be +# the only way to filter at the moment. +# +# This filter exclude the metrics sent for the hosts. +module "filter-tags-no-host" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "aws_beanstalk" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags_excluded = ["aws_cloudformation_logical-id:awsebautoscalinggroup"] +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/beanstalk/monitors-beanstalk.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/beanstalk/monitors-beanstalk.tf new file mode 100755 index 0000000..c620372 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/beanstalk/monitors-beanstalk.tf @@ -0,0 +1,110 @@ +### Beanstalk environment health ### +resource "datadog_monitor" "health" { + count = var.health_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Beanstalk Environment health {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}} : either degraded or severe){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}} : warning){{/is_warning}}" + message = coalesce(var.health_message, var.message) + type = "metric alert" + + query = <= ${var.health_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.health_threshold_critical + warning = var.health_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = var.notify_no_data + no_data_timeframe = var.health_no_data_timeframe + notify_audit = false + timeout_h = 0 + include_tags = true + require_full_window = false + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:beanstalk", "team:claranet", "created-by:terraform"], var.health_extra_tags) +} + +resource "datadog_monitor" "application_latency_p90" { + count = var.application_latency_p90_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Beanstalk Application latency p90 {{#is_alert}}{{{comparator}}} {{threshold}}sec ({{value}}sec){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}sec ({{value}}sec){{/is_warning}}" + message = coalesce(var.application_latency_p90_message, var.message) + type = "metric alert" + + query = <= ${var.application_latency_p90_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.application_latency_p90_threshold_critical + warning = var.application_latency_p90_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + require_full_window = false + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:beanstalk", "team:claranet", "created-by:terraform"], var.application_latency_p90_extra_tags) +} + +resource "datadog_monitor" "application_5xx_error_rate" { + count = var.application_5xx_error_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Beanstalk Application 5xx error rate {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.application_5xx_error_rate_message, var.message) + type = "query alert" + + query = < ${var.application_5xx_error_rate_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.application_5xx_error_rate_threshold_critical + warning = var.application_5xx_error_rate_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + require_full_window = false + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:beanstalk", "team:claranet", "created-by:terraform"], var.application_5xx_error_rate_extra_tags) +} + +resource "datadog_monitor" "root_filesystem_usage" { + count = var.root_filesystem_usage_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Beanstalk Instance root file system usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.root_filesystem_usage_message, var.message) + type = "metric alert" + + query = < ${var.root_filesystem_usage_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.root_filesystem_usage_threshold_critical + warning = var.root_filesystem_usage_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + timeout_h = var.root_filesystem_usage_timeout_h + include_tags = true + require_full_window = false + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:beanstalk", "team:claranet", "created-by:terraform"], var.root_filesystem_usage_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/beanstalk/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/beanstalk/outputs.tf new file mode 100755 index 0000000..ad6d3ed --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/beanstalk/outputs.tf @@ -0,0 +1,20 @@ +output "application_5xx_error_rate_id" { + description = "id for monitor application_5xx_error_rate" + value = datadog_monitor.application_5xx_error_rate.*.id +} + +output "application_latency_p90_id" { + description = "id for monitor application_latency_p90" + value = datadog_monitor.application_latency_p90.*.id +} + +output "health_id" { + description = "id for monitor health" + value = datadog_monitor.health.*.id +} + +output "root_filesystem_usage_id" { + description = "id for monitor root_filesystem_usage" + value = datadog_monitor.root_filesystem_usage.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/beanstalk/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/beanstalk/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/beanstalk/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/common/MANIFEST.txt b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/common/MANIFEST.txt new file mode 100755 index 0000000..3d83252 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/common/MANIFEST.txt @@ -0,0 +1 @@ +cloud-aws diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/common/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/common/README.md new file mode 100755 index 0000000..6e029a1 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/common/README.md @@ -0,0 +1,95 @@ +# CLOUD AWS ECS COMMON DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-ecs-common" { + source = "claranet/monitors/datadog//cloud/aws/ecs/common" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- ECS Service CPU Utilization High (disabled by default) +- ECS Service Memory Utilization High (disabled by default) +- ECS Service not healthy enough + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.service_cpu_utilization](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.service_memory_utilization](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.service_missing_tasks](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags](#input\_filter\_tags) | Tags used for filtering | `string` | `"*"` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [service\_cpu\_utilization\_enabled](#input\_service\_cpu\_utilization\_enabled) | Flag to enable Service CPU Utilization monitor | `string` | `"false"` | no | +| [service\_cpu\_utilization\_extra\_tags](#input\_service\_cpu\_utilization\_extra\_tags) | Extra tags for Service CPU Utilization monitor | `list(string)` | `[]` | no | +| [service\_cpu\_utilization\_message](#input\_service\_cpu\_utilization\_message) | Custom message for the Service CPU Utilization monitor | `string` | `""` | no | +| [service\_cpu\_utilization\_threshold\_critical](#input\_service\_cpu\_utilization\_threshold\_critical) | Critical threshold for the Service CPU Utilization monitor | `string` | `"90"` | no | +| [service\_cpu\_utilization\_threshold\_warning](#input\_service\_cpu\_utilization\_threshold\_warning) | Warning threshold for the Service CPU Utilization monitor | `string` | `"80"` | no | +| [service\_cpu\_utilization\_time\_aggregator](#input\_service\_cpu\_utilization\_time\_aggregator) | Monitor aggregator for Service CPU Utilization [available values: min, max or avg] | `string` | `"min"` | no | +| [service\_cpu\_utilization\_timeframe](#input\_service\_cpu\_utilization\_timeframe) | Timeframe for the Service CPU Utilization monitor | `string` | `"last_5m"` | no | +| [service\_memory\_utilization\_enabled](#input\_service\_memory\_utilization\_enabled) | Flag to enable Service Memory Utilization monitor | `string` | `"false"` | no | +| [service\_memory\_utilization\_extra\_tags](#input\_service\_memory\_utilization\_extra\_tags) | Extra tags for Service Memory Utilization monitor | `list(string)` | `[]` | no | +| [service\_memory\_utilization\_message](#input\_service\_memory\_utilization\_message) | Custom message for the Service Memory Utilization monitor | `string` | `""` | no | +| [service\_memory\_utilization\_threshold\_critical](#input\_service\_memory\_utilization\_threshold\_critical) | Critical threshold for the Service Memory Utilization monitor | `string` | `90` | no | +| [service\_memory\_utilization\_threshold\_warning](#input\_service\_memory\_utilization\_threshold\_warning) | Warning threshold for the Service Memory Utilization monitor | `string` | `85` | no | +| [service\_memory\_utilization\_time\_aggregator](#input\_service\_memory\_utilization\_time\_aggregator) | Monitor aggregator for Service Memory Utilization [available values: min, max or avg] | `string` | `"min"` | no | +| [service\_memory\_utilization\_timeframe](#input\_service\_memory\_utilization\_timeframe) | Timeframe for the Service Memory Utilization monitor | `string` | `"last_5m"` | no | +| [service\_missing\_tasks\_enabled](#input\_service\_missing\_tasks\_enabled) | Flag to enable Service Missing Tasks monitor | `string` | `"true"` | no | +| [service\_missing\_tasks\_extra\_tags](#input\_service\_missing\_tasks\_extra\_tags) | Extra tags for Service Missing Tasks monitor | `list(string)` | `[]` | no | +| [service\_missing\_tasks\_message](#input\_service\_missing\_tasks\_message) | Custom message for the Service Missing Tasks monitor | `string` | `""` | no | +| [service\_missing\_tasks\_threshold\_critical](#input\_service\_missing\_tasks\_threshold\_critical) | Critical threshold for the Service Missing Tasks monitor | `string` | `60` | no | +| [service\_missing\_tasks\_threshold\_warning](#input\_service\_missing\_tasks\_threshold\_warning) | Warning threshold for the Service Missing Tasks monitor | `string` | `80` | no | +| [service\_missing\_tasks\_time\_aggregator](#input\_service\_missing\_tasks\_time\_aggregator) | Monitor aggregator for Service Missing Tasks [available values: min, max or avg] | `string` | `"min"` | no | +| [service\_missing\_tasks\_timeframe](#input\_service\_missing\_tasks\_timeframe) | Timeframe for the Service Missing Tasks monitor | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [service\_cpu\_utilization\_id](#output\_service\_cpu\_utilization\_id) | id for monitor service\_cpu\_utilization | +| [service\_memory\_utilization\_id](#output\_service\_memory\_utilization\_id) | id for monitor service\_memory\_utilization | +| [service\_missing\_tasks\_id](#output\_service\_missing\_tasks\_id) | id for monitor service\_missing\_tasks | +## Related documentation + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/common/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/common/inputs.tf new file mode 100755 index 0000000..226f12a --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/common/inputs.tf @@ -0,0 +1,186 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags" { + description = "Tags used for filtering" + default = "*" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# +# Service CPU Utilization +# +variable "service_cpu_utilization_enabled" { + description = "Flag to enable Service CPU Utilization monitor" + type = string + default = "false" +} + +variable "service_cpu_utilization_extra_tags" { + description = "Extra tags for Service CPU Utilization monitor" + type = list(string) + default = [] +} + +variable "service_cpu_utilization_message" { + description = "Custom message for the Service CPU Utilization monitor" + type = string + default = "" +} + +variable "service_cpu_utilization_timeframe" { + description = "Timeframe for the Service CPU Utilization monitor" + type = string + default = "last_5m" +} + +variable "service_cpu_utilization_time_aggregator" { + description = "Monitor aggregator for Service CPU Utilization [available values: min, max or avg]" + type = string + default = "min" +} + +variable "service_cpu_utilization_threshold_critical" { + description = "Critical threshold for the Service CPU Utilization monitor" + type = string + default = "90" +} + +variable "service_cpu_utilization_threshold_warning" { + description = "Warning threshold for the Service CPU Utilization monitor" + type = string + default = "80" +} + +# +# Service Memory Utilization +# +variable "service_memory_utilization_enabled" { + description = "Flag to enable Service Memory Utilization monitor" + type = string + default = "false" +} + +variable "service_memory_utilization_extra_tags" { + description = "Extra tags for Service Memory Utilization monitor" + type = list(string) + default = [] +} + +variable "service_memory_utilization_message" { + description = "Custom message for the Service Memory Utilization monitor" + type = string + default = "" +} + +variable "service_memory_utilization_timeframe" { + description = "Timeframe for the Service Memory Utilization monitor" + type = string + default = "last_5m" +} + +variable "service_memory_utilization_time_aggregator" { + description = "Monitor aggregator for Service Memory Utilization [available values: min, max or avg]" + type = string + default = "min" +} + +variable "service_memory_utilization_threshold_critical" { + description = "Critical threshold for the Service Memory Utilization monitor" + type = string + default = 90 +} + +variable "service_memory_utilization_threshold_warning" { + description = "Warning threshold for the Service Memory Utilization monitor" + type = string + default = 85 +} + +# +# Service Missing tasks +# +variable "service_missing_tasks_enabled" { + description = "Flag to enable Service Missing Tasks monitor" + type = string + default = "true" +} + +variable "service_missing_tasks_extra_tags" { + description = "Extra tags for Service Missing Tasks monitor" + type = list(string) + default = [] +} + +variable "service_missing_tasks_message" { + description = "Custom message for the Service Missing Tasks monitor" + type = string + default = "" +} + +variable "service_missing_tasks_timeframe" { + description = "Timeframe for the Service Missing Tasks monitor" + type = string + default = "last_5m" +} + +variable "service_missing_tasks_time_aggregator" { + description = "Monitor aggregator for Service Missing Tasks [available values: min, max or avg]" + type = string + default = "min" +} + +variable "service_missing_tasks_threshold_critical" { + description = "Critical threshold for the Service Missing Tasks monitor" + type = string + default = 60 +} + +variable "service_missing_tasks_threshold_warning" { + description = "Warning threshold for the Service Missing Tasks monitor" + type = string + default = 80 +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/common/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/common/modules.tf new file mode 100755 index 0000000..cdaf5f1 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/common/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../../common/filter-tags" + + environment = var.environment + resource = "aws_ecs" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/common/monitors-ecs-common.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/common/monitors-ecs-common.tf new file mode 100755 index 0000000..2607570 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/common/monitors-ecs-common.tf @@ -0,0 +1,92 @@ +# Monitors related to services +resource "datadog_monitor" "service_cpu_utilization" { + count = var.service_cpu_utilization_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ECS Service CPU Utilization High {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.service_cpu_utilization_message, var.message) + type = "metric alert" + + query = < ${var.service_cpu_utilization_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.service_cpu_utilization_threshold_critical + warning = var.service_cpu_utilization_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:ecs", "team:claranet", "created-by:terraform", "category:service"], var.service_cpu_utilization_extra_tags) +} + +resource "datadog_monitor" "service_memory_utilization" { + count = var.service_memory_utilization_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ECS Service Memory Utilization High {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.service_memory_utilization_message, var.message) + type = "metric alert" + + query = < ${var.service_memory_utilization_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.service_memory_utilization_threshold_critical + warning = var.service_memory_utilization_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:ecs", "team:claranet", "created-by:terraform", "category:service"], var.service_memory_utilization_extra_tags) +} + +resource "datadog_monitor" "service_missing_tasks" { + count = var.service_missing_tasks_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ECS Service not healthy enough {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.service_missing_tasks_message, var.message) + type = "metric alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cluster_cpu_utilization](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.cluster_memory_reservation](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ecs_agent_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [agent\_status\_enabled](#input\_agent\_status\_enabled) | Flag to enable Agent Status monitor | `string` | `"true"` | no | +| [agent\_status\_extra\_tags](#input\_agent\_status\_extra\_tags) | Extra tags for Agent Status monitor | `list(string)` | `[]` | no | +| [agent\_status\_message](#input\_agent\_status\_message) | Custom message for the Agent Status monitor | `string` | `""` | no | +| [agent\_status\_no\_data\_timeframe](#input\_agent\_status\_no\_data\_timeframe) | Agent status does not respond monitor no data timeframe | `string` | `10` | no | +| [agent\_status\_threshold\_warning](#input\_agent\_status\_threshold\_warning) | Warning threshold for the Agent Status monitor | `string` | `3` | no | +| [cluster\_cpu\_utilization\_enabled](#input\_cluster\_cpu\_utilization\_enabled) | Flag to enable Cluster CPU utilization monitor | `string` | `"false"` | no | +| [cluster\_cpu\_utilization\_extra\_tags](#input\_cluster\_cpu\_utilization\_extra\_tags) | Extra tags for Cluster CPU utilization monitor | `list(string)` | `[]` | no | +| [cluster\_cpu\_utilization\_message](#input\_cluster\_cpu\_utilization\_message) | Custom message for the Cluster CPU Utilization monitor | `string` | `""` | no | +| [cluster\_cpu\_utilization\_threshold\_critical](#input\_cluster\_cpu\_utilization\_threshold\_critical) | Critical threshold for the Cluster CPU Utilization monitor | `string` | `90` | no | +| [cluster\_cpu\_utilization\_threshold\_warning](#input\_cluster\_cpu\_utilization\_threshold\_warning) | Warning threshold for the Cluster CPU Utilization monitor | `string` | `85` | no | +| [cluster\_cpu\_utilization\_time\_aggregator](#input\_cluster\_cpu\_utilization\_time\_aggregator) | Monitor aggregator for Cluster CPU Utilization [available values: min, max or avg] | `string` | `"min"` | no | +| [cluster\_cpu\_utilization\_timeframe](#input\_cluster\_cpu\_utilization\_timeframe) | Timeframe for the Cluster CPU Utilization monitor | `string` | `"last_5m"` | no | +| [cluster\_memory\_reservation\_enabled](#input\_cluster\_memory\_reservation\_enabled) | Flag to enable Cluster memory reservation monitor | `string` | `"false"` | no | +| [cluster\_memory\_reservation\_extra\_tags](#input\_cluster\_memory\_reservation\_extra\_tags) | Extra tags for Cluster Memory Reservation monitor | `list(string)` | `[]` | no | +| [cluster\_memory\_reservation\_message](#input\_cluster\_memory\_reservation\_message) | Custom message for the Cluster Memory Reservation monitor | `string` | `""` | no | +| [cluster\_memory\_reservation\_threshold\_critical](#input\_cluster\_memory\_reservation\_threshold\_critical) | Critical threshold for the Cluster Memory Reservation monitor | `string` | `90` | no | +| [cluster\_memory\_reservation\_threshold\_warning](#input\_cluster\_memory\_reservation\_threshold\_warning) | Warning threshold for the Cluster Memory Reservation monitor | `string` | `85` | no | +| [cluster\_memory\_reservation\_time\_aggregator](#input\_cluster\_memory\_reservation\_time\_aggregator) | Monitor aggregator for Cluster Memory Reservation [available values: min, max or avg] | `string` | `"min"` | no | +| [cluster\_memory\_reservation\_timeframe](#input\_cluster\_memory\_reservation\_timeframe) | Timeframe for the Cluster Memory Reservation monitor | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cluster\_cpu\_utilization\_id](#output\_cluster\_cpu\_utilization\_id) | id for monitor cluster\_cpu\_utilization | +| [cluster\_memory\_reservation\_id](#output\_cluster\_memory\_reservation\_id) | id for monitor cluster\_memory\_reservation | +| [ecs\_agent\_status\_id](#output\_ecs\_agent\_status\_id) | id for monitor ecs\_agent\_status | +## Related documentation + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/ec2-cluster/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/ec2-cluster/inputs.tf new file mode 100755 index 0000000..c9910f8 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/ec2-cluster/inputs.tf @@ -0,0 +1,170 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# +# Agent Status +# +variable "agent_status_enabled" { + description = "Flag to enable Agent Status monitor" + type = string + default = "true" +} + +variable "agent_status_extra_tags" { + description = "Extra tags for Agent Status monitor" + type = list(string) + default = [] +} + +variable "agent_status_message" { + description = "Custom message for the Agent Status monitor" + type = string + default = "" +} + +variable "agent_status_threshold_warning" { + description = "Warning threshold for the Agent Status monitor" + type = string + default = 3 +} + +variable "agent_status_no_data_timeframe" { + description = "Agent status does not respond monitor no data timeframe" + type = string + default = 10 +} + +# +# Cluster CPU Utilization +# +variable "cluster_cpu_utilization_enabled" { + description = "Flag to enable Cluster CPU utilization monitor" + type = string + default = "false" +} + +variable "cluster_cpu_utilization_extra_tags" { + description = "Extra tags for Cluster CPU utilization monitor" + type = list(string) + default = [] +} + +variable "cluster_cpu_utilization_message" { + description = "Custom message for the Cluster CPU Utilization monitor" + type = string + default = "" +} + +variable "cluster_cpu_utilization_time_aggregator" { + description = "Monitor aggregator for Cluster CPU Utilization [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cluster_cpu_utilization_timeframe" { + description = "Timeframe for the Cluster CPU Utilization monitor" + type = string + default = "last_5m" +} + +variable "cluster_cpu_utilization_threshold_critical" { + description = "Critical threshold for the Cluster CPU Utilization monitor" + type = string + default = 90 +} + +variable "cluster_cpu_utilization_threshold_warning" { + description = "Warning threshold for the Cluster CPU Utilization monitor" + type = string + default = 85 +} + + +# +# Cluster Memory Reservation +# +variable "cluster_memory_reservation_enabled" { + description = "Flag to enable Cluster memory reservation monitor" + type = string + default = "false" +} + +variable "cluster_memory_reservation_extra_tags" { + description = "Extra tags for Cluster Memory Reservation monitor" + type = list(string) + default = [] +} + +variable "cluster_memory_reservation_message" { + description = "Custom message for the Cluster Memory Reservation monitor" + type = string + default = "" +} + +variable "cluster_memory_reservation_time_aggregator" { + description = "Monitor aggregator for Cluster Memory Reservation [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cluster_memory_reservation_timeframe" { + description = "Timeframe for the Cluster Memory Reservation monitor" + type = string + default = "last_5m" +} + +variable "cluster_memory_reservation_threshold_critical" { + description = "Critical threshold for the Cluster Memory Reservation monitor" + type = string + default = 90 +} + +variable "cluster_memory_reservation_threshold_warning" { + description = "Warning threshold for the Cluster Memory Reservation monitor" + type = string + default = 85 +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/ec2-cluster/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/ec2-cluster/modules.tf new file mode 100755 index 0000000..cdaf5f1 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/ec2-cluster/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../../common/filter-tags" + + environment = var.environment + resource = "aws_ecs" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/ec2-cluster/monitors-ecs-ec2-cluster.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/ec2-cluster/monitors-ecs-ec2-cluster.tf new file mode 100755 index 0000000..2766414 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/ec2-cluster/monitors-ecs-ec2-cluster.tf @@ -0,0 +1,93 @@ +# Monitors related to ECS Cluster +resource "datadog_monitor" "ecs_agent_status" { + count = var.agent_status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ECS Agent disconnected {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.agent_status_message, var.message) + type = "service check" + + query = < ${var.cluster_cpu_utilization_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.cluster_cpu_utilization_threshold_critical + warning = var.cluster_cpu_utilization_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:ecs", "team:claranet", "created-by:terraform", "category:cluster"], var.cluster_cpu_utilization_extra_tags) + +} + +resource "datadog_monitor" "cluster_memory_reservation" { + count = var.cluster_memory_reservation_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ECS Cluster Memory Reservation High {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cluster_memory_reservation_message, var.message) + type = "metric alert" + + query = < ${var.cluster_memory_reservation_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.cluster_memory_reservation_threshold_critical + warning = var.cluster_memory_reservation_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:ecs", "team:claranet", "created-by:terraform", "category:cluster"], var.cluster_memory_reservation_extra_tags) +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/ec2-cluster/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/ec2-cluster/outputs.tf new file mode 100755 index 0000000..7d7b544 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/ec2-cluster/outputs.tf @@ -0,0 +1,15 @@ +output "cluster_cpu_utilization_id" { + description = "id for monitor cluster_cpu_utilization" + value = datadog_monitor.cluster_cpu_utilization.*.id +} + +output "cluster_memory_reservation_id" { + description = "id for monitor cluster_memory_reservation" + value = datadog_monitor.cluster_memory_reservation.*.id +} + +output "ecs_agent_status_id" { + description = "id for monitor ecs_agent_status" + value = datadog_monitor.ecs_agent_status.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/ec2-cluster/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/ec2-cluster/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/ec2-cluster/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/fargate/MANIFEST.txt b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/fargate/MANIFEST.txt new file mode 100755 index 0000000..3d83252 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/fargate/MANIFEST.txt @@ -0,0 +1 @@ +cloud-aws diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/fargate/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/fargate/README.md new file mode 100755 index 0000000..28f3ce0 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/fargate/README.md @@ -0,0 +1,99 @@ +# CLOUD AWS ECS FARGATE DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-ecs-fargate" { + source = "claranet/monitors/datadog//cloud/aws/ecs/fargate" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Fargate CPU Utilization High (disabled by default) +- Fargate memory Utilization High (disabled by default) +- Fargate service does not respond. + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cpu_utilization](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.memory_utilization](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.service_check](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_utilization\_enabled](#input\_cpu\_utilization\_enabled) | Flag to enable monitor | `string` | `"false"` | no | +| [cpu\_utilization\_extra\_tags](#input\_cpu\_utilization\_extra\_tags) | Extra tags for the monitor | `list(string)` | `[]` | no | +| [cpu\_utilization\_message](#input\_cpu\_utilization\_message) | Custom message for the monitor | `string` | `""` | no | +| [cpu\_utilization\_threshold\_critical](#input\_cpu\_utilization\_threshold\_critical) | Critical threshold for the monitor | `string` | `90` | no | +| [cpu\_utilization\_threshold\_warning](#input\_cpu\_utilization\_threshold\_warning) | Warning threshold for the monitor | `string` | `85` | no | +| [cpu\_utilization\_time\_aggregator](#input\_cpu\_utilization\_time\_aggregator) | Monitor aggregator (min, max or avg) | `string` | `"min"` | no | +| [cpu\_utilization\_timeframe](#input\_cpu\_utilization\_timeframe) | Timeframe for the monitor | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `bool` | `true` | no | +| [memory\_utilization\_enabled](#input\_memory\_utilization\_enabled) | Flag to enable Fargate Memory utilization monitor | `string` | `"false"` | no | +| [memory\_utilization\_extra\_tags](#input\_memory\_utilization\_extra\_tags) | Extra tags for Fargate Memory utilization monitor | `list(string)` | `[]` | no | +| [memory\_utilization\_message](#input\_memory\_utilization\_message) | Custom message for the Fargate Memory Utilization monitor | `string` | `""` | no | +| [memory\_utilization\_threshold\_critical](#input\_memory\_utilization\_threshold\_critical) | Critical threshold for the Fargate Memory Utilization monitor | `string` | `90` | no | +| [memory\_utilization\_threshold\_warning](#input\_memory\_utilization\_threshold\_warning) | Warning threshold for the Fargate Memory Utilization monitor | `string` | `85` | no | +| [memory\_utilization\_time\_aggregator](#input\_memory\_utilization\_time\_aggregator) | Monitor aggregator for Fargate Memory Utilization [available values: min, max or avg] | `string` | `"min"` | no | +| [memory\_utilization\_timeframe](#input\_memory\_utilization\_timeframe) | Timeframe for the Fargate Memory Utilization monitor | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `string` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [service\_check\_enabled](#input\_service\_check\_enabled) | Flag to enable monitor | `bool` | `true` | no | +| [service\_check\_extra\_tags](#input\_service\_check\_extra\_tags) | Extra tags for the monitor | `list(string)` | `[]` | no | +| [service\_check\_message](#input\_service\_check\_message) | Custom message for the monitor | `string` | `""` | no | +| [service\_check\_no\_data\_timeframe](#input\_service\_check\_no\_data\_timeframe) | No data timeframe in minutes | `number` | `10` | no | +| [service\_check\_threshold\_warning](#input\_service\_check\_threshold\_warning) | Warning threshold | `number` | `3` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cpu\_utilization\_id](#output\_cpu\_utilization\_id) | id for monitor cpu\_utilization | +| [memory\_utilization\_id](#output\_memory\_utilization\_id) | id for monitor memory\_utilization | +| [service\_check\_id](#output\_service\_check\_id) | id for monitor service\_check | +## Related documentation + +[Official DataDog documentation on ECS Fargate](https://docs.datadoghq.com/integrations/ecs_fargate/) + +### Specific configuration due to agent limitations + +CPU & memory monitors will be usable only when deploying datadog agent as a sidecar in task definitions. + +In order to avoid clutter on monitors, datadog agent & ECS internal containers are always excluded from filtering to be on par with Kubernetes way of work. A bug is [currently opened](https://github.com/DataDog/datadog-agent/issues/2722) on agent repository on this matter. diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/fargate/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/fargate/inputs.tf new file mode 100755 index 0000000..97be59f --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/fargate/inputs.tf @@ -0,0 +1,169 @@ +# Generics + +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "message" { + type = string + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + type = number + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + type = number + default = 300 +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + type = bool + default = true +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + type = bool + default = true +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + type = string + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + type = string + default = "" +} + +# Service checks +variable "service_check_enabled" { + type = bool + description = "Flag to enable monitor " + default = true +} + +variable "service_check_message" { + type = string + description = "Custom message for the monitor" + default = "" +} + +variable "service_check_extra_tags" { + type = list(string) + description = "Extra tags for the monitor" + default = [] +} + +variable "service_check_threshold_warning" { + type = number + description = "Warning threshold" + default = 3 +} + +variable "service_check_no_data_timeframe" { + type = number + description = "No data timeframe in minutes" + default = 10 +} + +# CPU utilization +variable "cpu_utilization_enabled" { + description = "Flag to enable monitor" + type = string + default = "false" +} + +variable "cpu_utilization_message" { + description = "Custom message for the monitor" + type = string + default = "" +} + +variable "cpu_utilization_time_aggregator" { + description = "Monitor aggregator (min, max or avg)" + type = string + default = "min" +} + +variable "cpu_utilization_timeframe" { + description = "Timeframe for the monitor" + type = string + default = "last_5m" +} + +variable "cpu_utilization_threshold_critical" { + description = "Critical threshold for the monitor" + type = string + default = 90 +} + +variable "cpu_utilization_threshold_warning" { + description = "Warning threshold for the monitor" + type = string + default = 85 +} + +variable "cpu_utilization_extra_tags" { + description = "Extra tags for the monitor" + type = list(string) + default = [] +} + +# Memory usage +variable "memory_utilization_enabled" { + description = "Flag to enable Fargate Memory utilization monitor" + type = string + default = "false" +} + +variable "memory_utilization_extra_tags" { + description = "Extra tags for Fargate Memory utilization monitor" + type = list(string) + default = [] +} + +variable "memory_utilization_message" { + description = "Custom message for the Fargate Memory Utilization monitor" + type = string + default = "" +} + +variable "memory_utilization_time_aggregator" { + description = "Monitor aggregator for Fargate Memory Utilization [available values: min, max or avg]" + type = string + default = "min" +} + +variable "memory_utilization_timeframe" { + description = "Timeframe for the Fargate Memory Utilization monitor" + type = string + default = "last_5m" +} + +variable "memory_utilization_threshold_critical" { + description = "Critical threshold for the Fargate Memory Utilization monitor" + type = string + default = 90 +} + +variable "memory_utilization_threshold_warning" { + description = "Warning threshold for the Fargate Memory Utilization monitor" + type = string + default = 85 +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/fargate/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/fargate/modules.tf new file mode 100755 index 0000000..6eaf996 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/fargate/modules.tf @@ -0,0 +1,14 @@ +module "filter-tags" { + + source = "../../../../common/filter-tags" + + environment = var.environment + resource = "aws_ecs" + extra_tags_excluded = [ + "ecs_container_name:datadog-agent", + "ecs_container_name:_internal_ecs_pause" + ] + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/fargate/monitors-ecs-fargate.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/fargate/monitors-ecs-fargate.tf new file mode 100755 index 0000000..d8d58fb --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/fargate/monitors-ecs-fargate.tf @@ -0,0 +1,97 @@ +# Service check + +resource "datadog_monitor" "service_check" { + count = var.service_check_enabled ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Fargate service does not respond." + message = coalesce(var.service_check_message, var.message) + type = "service check" + + query = < ${var.cpu_utilization_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.cpu_utilization_threshold_critical + warning = var.cpu_utilization_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + require_full_window = true + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:ecs_fargate", "team:claranet", "created-by:terraform"], var.cpu_utilization_extra_tags) + +} + +resource "datadog_monitor" "memory_utilization" { + count = var.memory_utilization_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Fargate memory Utilization High {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.memory_utilization_message, var.message) + type = "metric alert" + + query = < ${var.memory_utilization_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.memory_utilization_threshold_critical + warning = var.memory_utilization_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + require_full_window = true + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:ecs_fargate", "team:claranet", "created-by:terraform"], var.memory_utilization_extra_tags) + +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/fargate/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/fargate/outputs.tf new file mode 100755 index 0000000..6331f44 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/fargate/outputs.tf @@ -0,0 +1,15 @@ +output "cpu_utilization_id" { + description = "id for monitor cpu_utilization" + value = datadog_monitor.cpu_utilization.*.id +} + +output "memory_utilization_id" { + description = "id for monitor memory_utilization" + value = datadog_monitor.memory_utilization.*.id +} + +output "service_check_id" { + description = "id for monitor service_check" + value = datadog_monitor.service_check.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/fargate/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/fargate/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/ecs/fargate/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/common/MANIFEST.txt b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/common/MANIFEST.txt new file mode 100755 index 0000000..3d83252 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/common/MANIFEST.txt @@ -0,0 +1 @@ +cloud-aws diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/common/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/common/README.md new file mode 100755 index 0000000..c7b8a57 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/common/README.md @@ -0,0 +1,122 @@ +# CLOUD AWS ELASTICACHE COMMON DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-elasticache-common" { + source = "claranet/monitors/datadog//cloud/aws/elasticache/common" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Elasticache connections +- Elasticache eviction +- Elasticache evictions is growing +- Elasticache free memory +- Elasticache max connections reached +- Elasticache swap + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.elasticache_eviction](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.elasticache_eviction_growing](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.elasticache_free_memory](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.elasticache_max_connection](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.elasticache_no_connection](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.elasticache_swap](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [elasticache\_max\_connection\_no\_data\_timeframe](#input\_elasticache\_max\_connection\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [environment](#input\_environment) | Infrastructure Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [eviction\_enabled](#input\_eviction\_enabled) | Flag to enable Elasticache eviction monitor | `string` | `"true"` | no | +| [eviction\_extra\_tags](#input\_eviction\_extra\_tags) | Extra tags for Elasticache eviction monitor | `list(string)` | `[]` | no | +| [eviction\_growing\_condition\_timeframe](#input\_eviction\_growing\_condition\_timeframe) | Monitor condition timeframe for Elasticache eviction growing [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [eviction\_growing\_enabled](#input\_eviction\_growing\_enabled) | Flag to enable Elasticache eviction growing monitor | `string` | `"true"` | no | +| [eviction\_growing\_extra\_tags](#input\_eviction\_growing\_extra\_tags) | Extra tags for Elasticache eviction growing monitor | `list(string)` | `[]` | no | +| [eviction\_growing\_message](#input\_eviction\_growing\_message) | Custom message for Elasticache eviction growing monitor | `string` | `""` | no | +| [eviction\_growing\_threshold\_critical](#input\_eviction\_growing\_threshold\_critical) | Elasticache eviction growing critical threshold in percentage | `string` | `30` | no | +| [eviction\_growing\_threshold\_warning](#input\_eviction\_growing\_threshold\_warning) | Elasticache eviction growing warning threshold in percentage | `string` | `10` | no | +| [eviction\_growing\_timeframe](#input\_eviction\_growing\_timeframe) | Monitor timeframe for Elasticache eviction growing [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [eviction\_message](#input\_eviction\_message) | Custom message for Elasticache eviction monitor | `string` | `""` | no | +| [eviction\_threshold\_critical](#input\_eviction\_threshold\_critical) | Elasticache free memory critical threshold in percentage | `string` | `30` | no | +| [eviction\_threshold\_warning](#input\_eviction\_threshold\_warning) | Elasticache free memory warning threshold in percentage | `string` | `0` | no | +| [eviction\_timeframe](#input\_eviction\_timeframe) | Monitor timeframe for Elasticache eviction [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [free\_memory\_condition\_timeframe](#input\_free\_memory\_condition\_timeframe) | Monitor condition timeframe for Elasticache free memory [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [free\_memory\_enabled](#input\_free\_memory\_enabled) | Flag to enable Elasticache free memory monitor | `string` | `"true"` | no | +| [free\_memory\_extra\_tags](#input\_free\_memory\_extra\_tags) | Extra tags for Elasticache free memory monitor | `list(string)` | `[]` | no | +| [free\_memory\_message](#input\_free\_memory\_message) | Custom message for Elasticache free memory monitor | `string` | `""` | no | +| [free\_memory\_threshold\_critical](#input\_free\_memory\_threshold\_critical) | Elasticache free memory critical threshold in percentage | `string` | `-70` | no | +| [free\_memory\_threshold\_warning](#input\_free\_memory\_threshold\_warning) | Elasticache free memory warning threshold in percentage | `string` | `-50` | no | +| [free\_memory\_timeframe](#input\_free\_memory\_timeframe) | Monitor timeframe for Elasticache free memory [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [max\_connection\_enabled](#input\_max\_connection\_enabled) | Flag to enable Elasticache max connection monitor | `string` | `"true"` | no | +| [max\_connection\_extra\_tags](#input\_max\_connection\_extra\_tags) | Extra tags for Elasticache max connection monitor | `list(string)` | `[]` | no | +| [max\_connection\_message](#input\_max\_connection\_message) | Custom message for Elasticache max connection monitor | `string` | `""` | no | +| [max\_connection\_time\_aggregator](#input\_max\_connection\_time\_aggregator) | Monitor aggregator for Elasticache max connection [available values: min, max or avg] | `string` | `"max"` | no | +| [max\_connection\_timeframe](#input\_max\_connection\_timeframe) | Monitor timeframe for Elasticache max connection [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [no\_connection\_enabled](#input\_no\_connection\_enabled) | Flag to enable Elasticache no connection monitor | `string` | `"true"` | no | +| [no\_connection\_extra\_tags](#input\_no\_connection\_extra\_tags) | Extra tags for Elasticache no connection monitor | `list(string)` | `[]` | no | +| [no\_connection\_message](#input\_no\_connection\_message) | Custom message for Elasticache no connection monitor | `string` | `""` | no | +| [no\_connection\_time\_aggregator](#input\_no\_connection\_time\_aggregator) | Monitor aggregator for Elasticache no connection [available values: min, max or avg] | `string` | `"min"` | no | +| [no\_connection\_timeframe](#input\_no\_connection\_timeframe) | Monitor timeframe for Elasticache no connection [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [swap\_enabled](#input\_swap\_enabled) | Flag to enable Elasticache swap monitor | `string` | `"true"` | no | +| [swap\_extra\_tags](#input\_swap\_extra\_tags) | Extra tags for Elasticache swap monitor | `list(string)` | `[]` | no | +| [swap\_message](#input\_swap\_message) | Custom message for Elasticache swap monitor | `string` | `""` | no | +| [swap\_threshold\_critical](#input\_swap\_threshold\_critical) | Elasticache swap critical threshold in bytes | `string` | `50000000` | no | +| [swap\_threshold\_warning](#input\_swap\_threshold\_warning) | Elasticache swap warning threshold in bytes | `string` | `0` | no | +| [swap\_time\_aggregator](#input\_swap\_time\_aggregator) | Monitor aggregator for Elasticache memcached swap [available values: min, max or avg] | `string` | `"min"` | no | +| [swap\_timeframe](#input\_swap\_timeframe) | Monitor timeframe for Elasticache swap [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [elasticache\_eviction\_growing\_id](#output\_elasticache\_eviction\_growing\_id) | id for monitor elasticache\_eviction\_growing | +| [elasticache\_eviction\_id](#output\_elasticache\_eviction\_id) | id for monitor elasticache\_eviction | +| [elasticache\_free\_memory\_id](#output\_elasticache\_free\_memory\_id) | id for monitor elasticache\_free\_memory | +| [elasticache\_max\_connection\_id](#output\_elasticache\_max\_connection\_id) | id for monitor elasticache\_max\_connection | +| [elasticache\_no\_connection\_id](#output\_elasticache\_no\_connection\_id) | id for monitor elasticache\_no\_connection | +| [elasticache\_swap\_id](#output\_elasticache\_swap\_id) | id for monitor elasticache\_swap | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/amazon_elasticache/](https://docs.datadoghq.com/integrations/amazon_elasticache/) + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/common/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/common/inputs.tf new file mode 100755 index 0000000..75e9f5c --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/common/inputs.tf @@ -0,0 +1,276 @@ +# Global Terraform +variable "environment" { + description = "Infrastructure Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "elasticache_max_connection_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Elasticache specific + +variable "eviction_enabled" { + description = "Flag to enable Elasticache eviction monitor" + type = string + default = "true" +} + +variable "eviction_extra_tags" { + description = "Extra tags for Elasticache eviction monitor" + type = list(string) + default = [] +} + +variable "eviction_message" { + description = "Custom message for Elasticache eviction monitor" + type = string + default = "" +} + +variable "eviction_timeframe" { + description = "Monitor timeframe for Elasticache eviction [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "eviction_threshold_warning" { + description = "Elasticache free memory warning threshold in percentage" + type = string + default = 0 +} + +variable "eviction_threshold_critical" { + description = "Elasticache free memory critical threshold in percentage" + type = string + default = 30 +} + +variable "max_connection_enabled" { + description = "Flag to enable Elasticache max connection monitor" + type = string + default = "true" +} + +variable "max_connection_extra_tags" { + description = "Extra tags for Elasticache max connection monitor" + type = list(string) + default = [] +} + +variable "max_connection_message" { + description = "Custom message for Elasticache max connection monitor" + type = string + default = "" +} + +variable "max_connection_time_aggregator" { + description = "Monitor aggregator for Elasticache max connection [available values: min, max or avg]" + type = string + default = "max" +} + +variable "max_connection_timeframe" { + description = "Monitor timeframe for Elasticache max connection [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "no_connection_enabled" { + description = "Flag to enable Elasticache no connection monitor" + type = string + default = "true" +} + +variable "no_connection_extra_tags" { + description = "Extra tags for Elasticache no connection monitor" + type = list(string) + default = [] +} + +variable "no_connection_message" { + description = "Custom message for Elasticache no connection monitor" + type = string + default = "" +} + +variable "no_connection_time_aggregator" { + description = "Monitor aggregator for Elasticache no connection [available values: min, max or avg]" + type = string + default = "min" +} + +variable "no_connection_timeframe" { + description = "Monitor timeframe for Elasticache no connection [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "swap_enabled" { + description = "Flag to enable Elasticache swap monitor" + type = string + default = "true" +} + +variable "swap_extra_tags" { + description = "Extra tags for Elasticache swap monitor" + type = list(string) + default = [] +} + +variable "swap_message" { + description = "Custom message for Elasticache swap monitor" + type = string + default = "" +} + +variable "swap_time_aggregator" { + description = "Monitor aggregator for Elasticache memcached swap [available values: min, max or avg]" + type = string + default = "min" +} + +variable "swap_timeframe" { + description = "Monitor timeframe for Elasticache swap [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "swap_threshold_warning" { + description = "Elasticache swap warning threshold in bytes" + type = string + default = 0 +} + +variable "swap_threshold_critical" { + description = "Elasticache swap critical threshold in bytes" + type = string + default = 50000000 +} + +variable "free_memory_enabled" { + description = "Flag to enable Elasticache free memory monitor" + type = string + default = "true" +} + +variable "free_memory_extra_tags" { + description = "Extra tags for Elasticache free memory monitor" + type = list(string) + default = [] +} + +variable "free_memory_message" { + description = "Custom message for Elasticache free memory monitor" + type = string + default = "" +} + +variable "free_memory_condition_timeframe" { + description = "Monitor condition timeframe for Elasticache free memory [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "free_memory_timeframe" { + description = "Monitor timeframe for Elasticache free memory [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "free_memory_threshold_warning" { + description = "Elasticache free memory warning threshold in percentage" + type = string + default = -50 +} + +variable "free_memory_threshold_critical" { + description = "Elasticache free memory critical threshold in percentage" + type = string + default = -70 +} + +variable "eviction_growing_enabled" { + description = "Flag to enable Elasticache eviction growing monitor" + type = string + default = "true" +} + +variable "eviction_growing_extra_tags" { + description = "Extra tags for Elasticache eviction growing monitor" + type = list(string) + default = [] +} + +variable "eviction_growing_message" { + description = "Custom message for Elasticache eviction growing monitor" + type = string + default = "" +} + +variable "eviction_growing_condition_timeframe" { + description = "Monitor condition timeframe for Elasticache eviction growing [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "eviction_growing_timeframe" { + description = "Monitor timeframe for Elasticache eviction growing [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "eviction_growing_threshold_warning" { + description = "Elasticache eviction growing warning threshold in percentage" + type = string + default = 10 +} + +variable "eviction_growing_threshold_critical" { + description = "Elasticache eviction growing critical threshold in percentage" + type = string + default = 30 +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/common/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/common/modules.tf new file mode 100755 index 0000000..1b317be --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/common/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../../common/filter-tags" + + environment = var.environment + resource = "aws_elasticache" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/common/monitors-elasticache.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/common/monitors-elasticache.tf new file mode 100755 index 0000000..22154d4 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/common/monitors-elasticache.tf @@ -0,0 +1,171 @@ +resource "datadog_monitor" "elasticache_eviction" { + count = var.eviction_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticache eviction {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}" + message = coalesce(var.eviction_message, var.message) + type = "query alert" + + query = < ${var.eviction_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.eviction_threshold_warning + critical = var.eviction_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elasticache", "team:claranet", "created-by:terraform"], var.eviction_extra_tags) +} + +resource "datadog_monitor" "elasticache_max_connection" { + count = var.max_connection_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticache max connections reached {{#is_alert}}{{{comparator}}} {{threshold}} {{/is_alert}}" + message = coalesce(var.max_connection_message, var.message) + type = "query alert" + + query = <= 65000 +EOQ + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = var.notify_no_data + no_data_timeframe = var.elasticache_max_connection_no_data_timeframe + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elasticache", "team:claranet", "created-by:terraform"], var.max_connection_extra_tags) +} + +resource "datadog_monitor" "elasticache_no_connection" { + count = var.no_connection_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticache connections {{#is_alert}}{{{comparator}}} {{threshold}} {{/is_alert}}" + message = coalesce(var.no_connection_message, var.message) + type = "query alert" + + query = < ${var.swap_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.swap_threshold_warning + critical = var.swap_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elasticache", "team:claranet", "created-by:terraform"], var.swap_extra_tags) +} + +resource "datadog_monitor" "elasticache_free_memory" { + count = var.free_memory_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticache free memory {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.free_memory_message, var.message) + type = "query alert" + + query = < ${var.eviction_growing_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.eviction_growing_threshold_warning + critical = var.eviction_growing_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elasticache", "team:claranet", "created-by:terraform"], var.eviction_growing_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/common/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/common/outputs.tf new file mode 100755 index 0000000..cea5f6a --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/common/outputs.tf @@ -0,0 +1,30 @@ +output "elasticache_eviction_id" { + description = "id for monitor elasticache_eviction" + value = datadog_monitor.elasticache_eviction.*.id +} + +output "elasticache_eviction_growing_id" { + description = "id for monitor elasticache_eviction_growing" + value = datadog_monitor.elasticache_eviction_growing.*.id +} + +output "elasticache_free_memory_id" { + description = "id for monitor elasticache_free_memory" + value = datadog_monitor.elasticache_free_memory.*.id +} + +output "elasticache_max_connection_id" { + description = "id for monitor elasticache_max_connection" + value = datadog_monitor.elasticache_max_connection.*.id +} + +output "elasticache_no_connection_id" { + description = "id for monitor elasticache_no_connection" + value = datadog_monitor.elasticache_no_connection.*.id +} + +output "elasticache_swap_id" { + description = "id for monitor elasticache_swap" + value = datadog_monitor.elasticache_swap.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/common/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/common/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/common/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/memcached/MANIFEST.txt b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/memcached/MANIFEST.txt new file mode 100755 index 0000000..3d83252 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/memcached/MANIFEST.txt @@ -0,0 +1 @@ +cloud-aws diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/memcached/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/memcached/README.md new file mode 100755 index 0000000..078f471 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/memcached/README.md @@ -0,0 +1,91 @@ +# CLOUD AWS ELASTICACHE MEMCACHED DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-elasticache-memcached" { + source = "claranet/monitors/datadog//cloud/aws/elasticache/memcached" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Elasticache memcached cache hit ratio +- Elasticache memcached CPU + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.memcached_cpu_high](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.memcached_get_hits](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_high\_enabled](#input\_cpu\_high\_enabled) | Flag to enable Elasticache memcached cpu high monitor | `string` | `"true"` | no | +| [cpu\_high\_extra\_tags](#input\_cpu\_high\_extra\_tags) | Extra tags for Elasticache memcached cpu high monitor | `list(string)` | `[]` | no | +| [cpu\_high\_message](#input\_cpu\_high\_message) | Custom message for Elasticache memcached cpu high monitor | `string` | `""` | no | +| [cpu\_high\_threshold\_critical](#input\_cpu\_high\_threshold\_critical) | Elasticache memcached cpu high critical threshold in percentage | `string` | `90` | no | +| [cpu\_high\_threshold\_warning](#input\_cpu\_high\_threshold\_warning) | Elasticache memcached cpu high warning threshold in percentage | `string` | `75` | no | +| [cpu\_high\_time\_aggregator](#input\_cpu\_high\_time\_aggregator) | Monitor aggregator for Elasticache memcached cpu high [available values: min, max or avg] | `string` | `"min"` | no | +| [cpu\_high\_timeframe](#input\_cpu\_high\_timeframe) | Monitor timeframe for Elasticache memcached cpu high [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [environment](#input\_environment) | Infrastructure Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [get\_hits\_enabled](#input\_get\_hits\_enabled) | Flag to enable Elasticache memcached get hits monitor | `string` | `"true"` | no | +| [get\_hits\_extra\_tags](#input\_get\_hits\_extra\_tags) | Extra tags for Elasticache memcached get hits monitor | `list(string)` | `[]` | no | +| [get\_hits\_message](#input\_get\_hits\_message) | Custom message for Elasticache memcached get hits monitor | `string` | `""` | no | +| [get\_hits\_threshold\_critical](#input\_get\_hits\_threshold\_critical) | Elasticache memcached get hits critical threshold in percentage | `string` | `60` | no | +| [get\_hits\_threshold\_warning](#input\_get\_hits\_threshold\_warning) | Elasticache memcached get hits warning threshold in percentage | `string` | `80` | no | +| [get\_hits\_time\_aggregator](#input\_get\_hits\_time\_aggregator) | Monitor aggregator for Elasticache memcached get hits [available values: min, max or avg] | `string` | `"max"` | no | +| [get\_hits\_timeframe](#input\_get\_hits\_timeframe) | Monitor timeframe for Elasticache memcached get hits [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [memcached\_cpu\_high\_no\_data\_timeframe](#input\_memcached\_cpu\_high\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `30` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [memcached\_cpu\_high\_id](#output\_memcached\_cpu\_high\_id) | id for monitor memcached\_cpu\_high | +| [memcached\_get\_hits\_id](#output\_memcached\_get\_hits\_id) | id for monitor memcached\_get\_hits | +## Related documentation + +DataDog documentation: + +* [https://docs.datadoghq.com/integrations/amazon_elasticache/](https://docs.datadoghq.com/integrations/amazon_elasticache/) +* [https://www.datadoghq.com/blog/monitoring-elasticache-performance-metrics-with-redis-or-memcached/](https://www.datadoghq.com/blog/monitoring-elasticache-performance-metrics-with-redis-or-memcached/) + + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/memcached/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/memcached/inputs.tf new file mode 100755 index 0000000..d7ba1c9 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/memcached/inputs.tf @@ -0,0 +1,138 @@ +# Global Terraform +variable "environment" { + description = "Infrastructure Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "memcached_cpu_high_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 30 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Memcached specific + +variable "get_hits_enabled" { + description = "Flag to enable Elasticache memcached get hits monitor" + type = string + default = "true" +} + +variable "get_hits_extra_tags" { + description = "Extra tags for Elasticache memcached get hits monitor" + type = list(string) + default = [] +} + +variable "get_hits_message" { + description = "Custom message for Elasticache memcached get hits monitor" + type = string + default = "" +} + +variable "get_hits_time_aggregator" { + description = "Monitor aggregator for Elasticache memcached get hits [available values: min, max or avg]" + type = string + default = "max" +} + +variable "get_hits_timeframe" { + description = "Monitor timeframe for Elasticache memcached get hits [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "get_hits_threshold_warning" { + description = "Elasticache memcached get hits warning threshold in percentage" + type = string + default = 80 +} + +variable "get_hits_threshold_critical" { + description = "Elasticache memcached get hits critical threshold in percentage" + type = string + default = 60 +} + +variable "cpu_high_enabled" { + description = "Flag to enable Elasticache memcached cpu high monitor" + type = string + default = "true" +} + +variable "cpu_high_extra_tags" { + description = "Extra tags for Elasticache memcached cpu high monitor" + type = list(string) + default = [] +} + +variable "cpu_high_message" { + description = "Custom message for Elasticache memcached cpu high monitor" + type = string + default = "" +} + +variable "cpu_high_time_aggregator" { + description = "Monitor aggregator for Elasticache memcached cpu high [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cpu_high_timeframe" { + description = "Monitor timeframe for Elasticache memcached cpu high [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "cpu_high_threshold_warning" { + description = "Elasticache memcached cpu high warning threshold in percentage" + type = string + default = 75 +} + +variable "cpu_high_threshold_critical" { + description = "Elasticache memcached cpu high critical threshold in percentage" + type = string + default = 90 +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/memcached/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/memcached/modules.tf new file mode 100755 index 0000000..1b317be --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/memcached/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../../common/filter-tags" + + environment = var.environment + resource = "aws_elasticache" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/memcached/monitors-memcached.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/memcached/monitors-memcached.tf new file mode 100755 index 0000000..9bb1a4c --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/memcached/monitors-memcached.tf @@ -0,0 +1,63 @@ +resource "datadog_monitor" "memcached_get_hits" { + count = var.get_hits_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticache memcached cache hit ratio {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.get_hits_message, var.message) + type = "query alert" + + query = < ${var.cpu_high_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.cpu_high_threshold_warning + critical = var.cpu_high_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = var.notify_no_data + no_data_timeframe = var.memcached_cpu_high_no_data_timeframe + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elasticache-memcached", "team:claranet", "created-by:terraform", "engine:memcached"], var.cpu_high_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/memcached/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/memcached/outputs.tf new file mode 100755 index 0000000..a5a89e3 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/memcached/outputs.tf @@ -0,0 +1,10 @@ +output "memcached_cpu_high_id" { + description = "id for monitor memcached_cpu_high" + value = datadog_monitor.memcached_cpu_high.*.id +} + +output "memcached_get_hits_id" { + description = "id for monitor memcached_get_hits" + value = datadog_monitor.memcached_get_hits.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/memcached/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/memcached/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/memcached/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/redis/MANIFEST.txt b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/redis/MANIFEST.txt new file mode 100755 index 0000000..3d83252 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/redis/MANIFEST.txt @@ -0,0 +1 @@ +cloud-aws diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/redis/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/redis/README.md new file mode 100755 index 0000000..07c2bd0 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/redis/README.md @@ -0,0 +1,106 @@ +# CLOUD AWS ELASTICACHE REDIS DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-elasticache-redis" { + source = "claranet/monitors/datadog//cloud/aws/elasticache/redis" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Elasticache redis cache hit ratio +- Elasticache redis CPU +- Elasticache redis is receiving no commands +- Elasticache redis replication lag + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.redis_cache_hits](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.redis_commands](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.redis_cpu_high](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.redis_replication_lag](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cache\_hits\_enabled](#input\_cache\_hits\_enabled) | Flag to enable Elasticache redis cache hits monitor | `string` | `"true"` | no | +| [cache\_hits\_extra\_tags](#input\_cache\_hits\_extra\_tags) | Extra tags for Elasticache redis cache hits monitor | `list(string)` | `[]` | no | +| [cache\_hits\_message](#input\_cache\_hits\_message) | Custom message for Elasticache redis cache hits monitor | `string` | `""` | no | +| [cache\_hits\_threshold\_critical](#input\_cache\_hits\_threshold\_critical) | Elasticache redis cache hits critical threshold in percentage | `string` | `60` | no | +| [cache\_hits\_threshold\_warning](#input\_cache\_hits\_threshold\_warning) | Elasticache redis cache hits warning threshold in percentage | `string` | `80` | no | +| [cache\_hits\_time\_aggregator](#input\_cache\_hits\_time\_aggregator) | Monitor aggregator for Elasticache redis cache hits [available values: min, max or avg] | `string` | `"max"` | no | +| [cache\_hits\_timeframe](#input\_cache\_hits\_timeframe) | Monitor timeframe for Elasticache redis cache hits [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [commands\_enabled](#input\_commands\_enabled) | Flag to enable Elasticache redis commands monitor | `string` | `"true"` | no | +| [commands\_extra\_tags](#input\_commands\_extra\_tags) | Extra tags for Elasticache redis commands monitor | `list(string)` | `[]` | no | +| [commands\_message](#input\_commands\_message) | Custom message for Elasticache redis commands monitor | `string` | `""` | no | +| [commands\_timeframe](#input\_commands\_timeframe) | Monitor timeframe for Elasticache redis commands [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [cpu\_high\_enabled](#input\_cpu\_high\_enabled) | Flag to enable Elasticache redis cpu high monitor | `string` | `"true"` | no | +| [cpu\_high\_extra\_tags](#input\_cpu\_high\_extra\_tags) | Extra tags for Elasticache redis cpu high monitor | `list(string)` | `[]` | no | +| [cpu\_high\_message](#input\_cpu\_high\_message) | Custom message for Elasticache redis cpu high monitor | `string` | `""` | no | +| [cpu\_high\_threshold\_critical](#input\_cpu\_high\_threshold\_critical) | Elasticache redis cpu high critical threshold in percentage | `string` | `90` | no | +| [cpu\_high\_threshold\_warning](#input\_cpu\_high\_threshold\_warning) | Elasticache redis cpu high warning threshold in percentage | `string` | `75` | no | +| [cpu\_high\_time\_aggregator](#input\_cpu\_high\_time\_aggregator) | Monitor aggregator for Elasticache redis cpu high [available values: min, max or avg] | `string` | `"min"` | no | +| [cpu\_high\_timeframe](#input\_cpu\_high\_timeframe) | Monitor timeframe for Elasticache redis cpu high [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [environment](#input\_environment) | Infrastructure Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [redis\_cpu\_high\_no\_data\_timeframe](#input\_redis\_cpu\_high\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `30` | no | +| [replication\_lag\_enabled](#input\_replication\_lag\_enabled) | Flag to enable Elasticache redis replication lag monitor | `string` | `"true"` | no | +| [replication\_lag\_extra\_tags](#input\_replication\_lag\_extra\_tags) | Extra tags for Elasticache redis replication lag monitor | `list(string)` | `[]` | no | +| [replication\_lag\_message](#input\_replication\_lag\_message) | Custom message for Elasticache redis replication lag monitor | `string` | `""` | no | +| [replication\_lag\_threshold\_critical](#input\_replication\_lag\_threshold\_critical) | Elasticache redis replication lag critical threshold in seconds | `string` | `180` | no | +| [replication\_lag\_threshold\_warning](#input\_replication\_lag\_threshold\_warning) | Elasticache redis replication lag warning threshold in seconds | `string` | `90` | no | +| [replication\_lag\_time\_aggregator](#input\_replication\_lag\_time\_aggregator) | Monitor aggregator for Elasticache redis replication lag [available values: min, max or avg] | `string` | `"min"` | no | +| [replication\_lag\_timeframe](#input\_replication\_lag\_timeframe) | Monitor timeframe for Elasticache redis replication lag [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_10m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [redis\_cache\_hits\_id](#output\_redis\_cache\_hits\_id) | id for monitor redis\_cache\_hits | +| [redis\_commands\_id](#output\_redis\_commands\_id) | id for monitor redis\_commands | +| [redis\_cpu\_high\_id](#output\_redis\_cpu\_high\_id) | id for monitor redis\_cpu\_high | +| [redis\_replication\_lag\_id](#output\_redis\_replication\_lag\_id) | id for monitor redis\_replication\_lag | +## Related documentation + +* [https://docs.datadoghq.com/integrations/amazon_elasticache/](https://docs.datadoghq.com/integrations/amazon_elasticache/) +* [https://www.datadoghq.com/blog/monitoring-elasticache-performance-metrics-with-redis-or-memcached/](https://www.datadoghq.com/blog/monitoring-elasticache-performance-metrics-with-redis-or-memcached/) + + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/redis/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/redis/inputs.tf new file mode 100755 index 0000000..7e391cf --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/redis/inputs.tf @@ -0,0 +1,204 @@ +# Global Terraform +variable "environment" { + description = "Infrastructure Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "redis_cpu_high_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 30 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# redis specific + +variable "cache_hits_enabled" { + description = "Flag to enable Elasticache redis cache hits monitor" + type = string + default = "true" +} + +variable "cache_hits_extra_tags" { + description = "Extra tags for Elasticache redis cache hits monitor" + type = list(string) + default = [] +} + +variable "cache_hits_message" { + description = "Custom message for Elasticache redis cache hits monitor" + type = string + default = "" +} + +variable "cache_hits_time_aggregator" { + description = "Monitor aggregator for Elasticache redis cache hits [available values: min, max or avg]" + type = string + default = "max" +} + +variable "cache_hits_timeframe" { + description = "Monitor timeframe for Elasticache redis cache hits [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "cache_hits_threshold_warning" { + description = "Elasticache redis cache hits warning threshold in percentage" + type = string + default = 80 +} + +variable "cache_hits_threshold_critical" { + description = "Elasticache redis cache hits critical threshold in percentage" + type = string + default = 60 +} + +variable "cpu_high_enabled" { + description = "Flag to enable Elasticache redis cpu high monitor" + type = string + default = "true" +} + +variable "cpu_high_extra_tags" { + description = "Extra tags for Elasticache redis cpu high monitor" + type = list(string) + default = [] +} + +variable "cpu_high_message" { + description = "Custom message for Elasticache redis cpu high monitor" + type = string + default = "" +} + +variable "cpu_high_time_aggregator" { + description = "Monitor aggregator for Elasticache redis cpu high [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cpu_high_timeframe" { + description = "Monitor timeframe for Elasticache redis cpu high [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "cpu_high_threshold_warning" { + description = "Elasticache redis cpu high warning threshold in percentage" + type = string + default = 75 +} + +variable "cpu_high_threshold_critical" { + description = "Elasticache redis cpu high critical threshold in percentage" + type = string + default = 90 +} + +variable "replication_lag_enabled" { + description = "Flag to enable Elasticache redis replication lag monitor" + type = string + default = "true" +} + +variable "replication_lag_extra_tags" { + description = "Extra tags for Elasticache redis replication lag monitor" + type = list(string) + default = [] +} + +variable "replication_lag_message" { + description = "Custom message for Elasticache redis replication lag monitor" + type = string + default = "" +} + +variable "replication_lag_time_aggregator" { + description = "Monitor aggregator for Elasticache redis replication lag [available values: min, max or avg]" + type = string + default = "min" +} + +variable "replication_lag_timeframe" { + description = "Monitor timeframe for Elasticache redis replication lag [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_10m" +} + +variable "replication_lag_threshold_warning" { + description = "Elasticache redis replication lag warning threshold in seconds" + type = string + default = 90 +} + +variable "replication_lag_threshold_critical" { + description = "Elasticache redis replication lag critical threshold in seconds" + type = string + default = 180 +} + +variable "commands_enabled" { + description = "Flag to enable Elasticache redis commands monitor" + type = string + default = "true" +} + +variable "commands_extra_tags" { + description = "Extra tags for Elasticache redis commands monitor" + type = list(string) + default = [] +} + +variable "commands_message" { + description = "Custom message for Elasticache redis commands monitor" + type = string + default = "" +} + +variable "commands_timeframe" { + description = "Monitor timeframe for Elasticache redis commands [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/redis/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/redis/modules.tf new file mode 100755 index 0000000..1b317be --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/redis/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../../common/filter-tags" + + environment = var.environment + resource = "aws_elasticache" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/redis/monitors-redis.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/redis/monitors-redis.tf new file mode 100755 index 0000000..1a9466b --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticache/redis/monitors-redis.tf @@ -0,0 +1,114 @@ +resource "datadog_monitor" "redis_cache_hits" { + count = var.cache_hits_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticache redis cache hit ratio {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cache_hits_message, var.message) + type = "query alert" + + query = < ${var.cpu_high_threshold_critical} +EOQ + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = var.notify_no_data + no_data_timeframe = var.redis_cpu_high_no_data_timeframe + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elasticache-redis", "team:claranet", "created-by:terraform", "engine:redis"], var.cpu_high_extra_tags) +} + +resource "datadog_monitor" "redis_replication_lag" { + count = var.replication_lag_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticache redis replication lag {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + message = coalesce(var.replication_lag_message, var.message) + type = "query alert" + + query = < ${var.replication_lag_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.replication_lag_threshold_warning + critical = var.replication_lag_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elasticache-redis", "team:claranet", "created-by:terraform", "engine:redis"], var.replication_lag_extra_tags) +} + +resource "datadog_monitor" "redis_commands" { + count = var.commands_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticache redis is receiving no commands" + message = coalesce(var.commands_message, var.message) + type = "query alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.es_cluster_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.es_cpu_90_15min](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.es_free_space_low](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_enabled](#input\_cpu\_enabled) | Flag to enable ES cluster cpu monitor | `string` | `"true"` | no | +| [cpu\_extra\_tags](#input\_cpu\_extra\_tags) | Extra tags for ES cluster cpu monitor | `list(string)` | `[]` | no | +| [cpu\_message](#input\_cpu\_message) | Custom message for ES cluster cpu monitor | `string` | `""` | no | +| [cpu\_threshold\_critical](#input\_cpu\_threshold\_critical) | CPU usage in percent (critical threshold) | `string` | `"90"` | no | +| [cpu\_threshold\_warning](#input\_cpu\_threshold\_warning) | CPU usage in percent (warning threshold) | `string` | `"80"` | no | +| [cpu\_time\_aggregator](#input\_cpu\_time\_aggregator) | Monitor aggregator for ES cluster cpu [available values: min, max or avg] | `string` | `"min"` | no | +| [cpu\_timeframe](#input\_cpu\_timeframe) | Monitor timeframe for ES cluster cpu [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [diskspace\_enabled](#input\_diskspace\_enabled) | Flag to enable ES cluster diskspace monitor | `string` | `"true"` | no | +| [diskspace\_extra\_tags](#input\_diskspace\_extra\_tags) | Extra tags for ES cluster diskspace monitor | `list(string)` | `[]` | no | +| [diskspace\_message](#input\_diskspace\_message) | Custom message for ES cluster diskspace monitor | `string` | `""` | no | +| [diskspace\_threshold\_critical](#input\_diskspace\_threshold\_critical) | Disk free space in percent (critical threshold) | `string` | `"10"` | no | +| [diskspace\_threshold\_warning](#input\_diskspace\_threshold\_warning) | Disk free space in percent (warning threshold) | `string` | `"20"` | no | +| [diskspace\_time\_aggregator](#input\_diskspace\_time\_aggregator) | Monitor aggregator for ES cluster diskspace [available values: min, max or avg] | `string` | `"max"` | no | +| [diskspace\_timeframe](#input\_diskspace\_timeframe) | Monitor timeframe for ES cluster diskspace [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [es\_cluster\_status\_enabled](#input\_es\_cluster\_status\_enabled) | Flag to enable ES cluster status monitor | `string` | `"true"` | no | +| [es\_cluster\_status\_extra\_tags](#input\_es\_cluster\_status\_extra\_tags) | Extra tags for ES cluster status monitor | `list(string)` | `[]` | no | +| [es\_cluster\_status\_message](#input\_es\_cluster\_status\_message) | Custom message for ES cluster status monitor | `string` | `""` | no | +| [es\_cluster\_status\_no\_data\_timeframe](#input\_es\_cluster\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `60` | no | +| [es\_cluster\_status\_timeframe](#input\_es\_cluster\_status\_timeframe) | Monitor timeframe for ES cluster status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_30m"` | no | +| [es\_cluster\_volume\_size](#input\_es\_cluster\_volume\_size) | ElasticSearch Domain volume size (in GB) | `any` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [es\_cluster\_status\_id](#output\_es\_cluster\_status\_id) | id for monitor es\_cluster\_status | +| [es\_cpu\_90\_15min\_id](#output\_es\_cpu\_90\_15min\_id) | id for monitor es\_cpu\_90\_15min | +| [es\_free\_space\_low\_id](#output\_es\_free\_space\_low\_id) | id for monitor es\_free\_space\_low | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/amazon_es/](https://docs.datadoghq.com/integrations/amazon_es/) + +AWS ElasticSearch Service Instance metrics documentation: [https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/es-metricscollected.html](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/es-metricscollected.html) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticsearch/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticsearch/inputs.tf new file mode 100755 index 0000000..8fa1648 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticsearch/inputs.tf @@ -0,0 +1,162 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "es_cluster_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 60 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# AWS ElasticSearch Service specific + +variable "es_cluster_status_enabled" { + description = "Flag to enable ES cluster status monitor" + type = string + default = "true" +} + +variable "es_cluster_status_extra_tags" { + description = "Extra tags for ES cluster status monitor" + type = list(string) + default = [] +} + +variable "es_cluster_status_message" { + description = "Custom message for ES cluster status monitor" + type = string + default = "" +} + +variable "es_cluster_status_timeframe" { + description = "Monitor timeframe for ES cluster status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_30m" +} + +variable "es_cluster_volume_size" { + description = "ElasticSearch Domain volume size (in GB)" +} + +variable "diskspace_enabled" { + description = "Flag to enable ES cluster diskspace monitor" + type = string + default = "true" +} + +variable "diskspace_extra_tags" { + description = "Extra tags for ES cluster diskspace monitor" + type = list(string) + default = [] +} + +variable "diskspace_message" { + description = "Custom message for ES cluster diskspace monitor" + type = string + default = "" +} + +variable "diskspace_time_aggregator" { + description = "Monitor aggregator for ES cluster diskspace [available values: min, max or avg]" + type = string + default = "max" +} + +variable "diskspace_timeframe" { + description = "Monitor timeframe for ES cluster diskspace [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "diskspace_threshold_warning" { + description = "Disk free space in percent (warning threshold)" + default = "20" +} + +variable "diskspace_threshold_critical" { + description = "Disk free space in percent (critical threshold)" + default = "10" +} + +variable "cpu_enabled" { + description = "Flag to enable ES cluster cpu monitor" + type = string + default = "true" +} + +variable "cpu_extra_tags" { + description = "Extra tags for ES cluster cpu monitor" + type = list(string) + default = [] +} + +variable "cpu_message" { + description = "Custom message for ES cluster cpu monitor" + type = string + default = "" +} + +variable "cpu_time_aggregator" { + description = "Monitor aggregator for ES cluster cpu [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cpu_timeframe" { + description = "Monitor timeframe for ES cluster cpu [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "cpu_threshold_warning" { + description = "CPU usage in percent (warning threshold)" + default = "80" +} + +variable "cpu_threshold_critical" { + description = "CPU usage in percent (critical threshold)" + default = "90" +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticsearch/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticsearch/modules.tf new file mode 100755 index 0000000..e259384 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticsearch/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "aws_elasticsearch" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticsearch/monitors-elasticsearch.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticsearch/monitors-elasticsearch.tf new file mode 100755 index 0000000..bd73e31 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticsearch/monitors-elasticsearch.tf @@ -0,0 +1,100 @@ +### Elasticsearch cluster status monitor ### +/* Note about the query + - If aws.es.cluster_statusred is 1 --> query value (= 2.1) > 2 : critical + - If aws.es.cluster_statusyellow is 1 --> 1 < query value (=1.1) < 2 : warning + Workaround : in the query, we add "0.1" to the result and we use the comparator ">=". No alert was triggered without that. */ +resource "datadog_monitor" "es_cluster_status" { + count = var.es_cluster_status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ElasticSearch cluster status is not green" + message = coalesce(var.es_cluster_status_message, var.message) + type = "query alert" + + query = <= 2 +EOQ + + monitor_thresholds { + warning = 1 + critical = 2 + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = var.notify_no_data + no_data_timeframe = var.es_cluster_status_no_data_timeframe + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.es_cluster_status_extra_tags) +} + +### Elasticsearch cluster free storage space monitor ### +resource "datadog_monitor" "es_free_space_low" { + count = var.diskspace_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ElasticSearch cluster free storage space {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.diskspace_message, var.message) + type = "query alert" + + query = < ${var.cpu_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.cpu_threshold_warning + critical = var.cpu_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.cpu_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticsearch/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticsearch/outputs.tf new file mode 100755 index 0000000..b55a5a2 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticsearch/outputs.tf @@ -0,0 +1,15 @@ +output "es_cluster_status_id" { + description = "id for monitor es_cluster_status" + value = datadog_monitor.es_cluster_status.*.id +} + +output "es_cpu_90_15min_id" { + description = "id for monitor es_cpu_90_15min" + value = datadog_monitor.es_cpu_90_15min.*.id +} + +output "es_free_space_low_id" { + description = "id for monitor es_free_space_low" + value = datadog_monitor.es_free_space_low.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticsearch/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticsearch/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elasticsearch/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elb/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elb/README.md new file mode 100755 index 0000000..174cf84 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elb/README.md @@ -0,0 +1,124 @@ +# CLOUD AWS ELB DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-elb" { + source = "claranet/monitors/datadog//cloud/aws/elb" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- ELB 4xx errors too high +- ELB 5xx errors too high +- ELB backend 4xx errors too high +- ELB backend 5xx errors too high +- ELB healthy instances +- ELB latency too high + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.ELB_backend_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ELB_no_healthy_instances](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ELB_too_much_4xx](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ELB_too_much_4xx_backend](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ELB_too_much_5xx](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ELB_too_much_5xx_backend](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [artificial\_requests\_count](#input\_artificial\_requests\_count) | Number of false requests used to mitigate false positive in case of low trafic | `number` | `5` | no | +| [elb\_4xx\_enabled](#input\_elb\_4xx\_enabled) | Flag to enable ELB 4xx errors monitor | `string` | `"true"` | no | +| [elb\_4xx\_extra\_tags](#input\_elb\_4xx\_extra\_tags) | Extra tags for ELB 4xx errors monitor | `list(string)` | `[]` | no | +| [elb\_4xx\_message](#input\_elb\_4xx\_message) | Custom message for ELB 4xx errors monitor | `string` | `""` | no | +| [elb\_4xx\_threshold\_critical](#input\_elb\_4xx\_threshold\_critical) | loadbalancer 4xx critical threshold in percentage | `number` | `10` | no | +| [elb\_4xx\_threshold\_warning](#input\_elb\_4xx\_threshold\_warning) | loadbalancer 4xx warning threshold in percentage | `number` | `5` | no | +| [elb\_4xx\_timeframe](#input\_elb\_4xx\_timeframe) | Monitor timeframe for ELB 4xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [elb\_5xx\_enabled](#input\_elb\_5xx\_enabled) | Flag to enable ELB 5xx errors monitor | `string` | `"true"` | no | +| [elb\_5xx\_extra\_tags](#input\_elb\_5xx\_extra\_tags) | Extra tags for ELB 5xx errors monitor | `list(string)` | `[]` | no | +| [elb\_5xx\_message](#input\_elb\_5xx\_message) | Custom message for ELB 5xx errors monitor | `string` | `""` | no | +| [elb\_5xx\_threshold\_critical](#input\_elb\_5xx\_threshold\_critical) | loadbalancer 5xx critical threshold in percentage | `number` | `10` | no | +| [elb\_5xx\_threshold\_warning](#input\_elb\_5xx\_threshold\_warning) | loadbalancer 5xx warning threshold in percentage | `number` | `5` | no | +| [elb\_5xx\_timeframe](#input\_elb\_5xx\_timeframe) | Monitor timeframe for ELB 5xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [elb\_backend\_4xx\_enabled](#input\_elb\_backend\_4xx\_enabled) | Flag to enable ELB backend 4xx errors monitor | `string` | `"true"` | no | +| [elb\_backend\_4xx\_extra\_tags](#input\_elb\_backend\_4xx\_extra\_tags) | Extra tags for ELB backend 4xx errors monitor | `list(string)` | `[]` | no | +| [elb\_backend\_4xx\_message](#input\_elb\_backend\_4xx\_message) | Custom message for ELB backend 4xx errors monitor | `string` | `""` | no | +| [elb\_backend\_4xx\_threshold\_critical](#input\_elb\_backend\_4xx\_threshold\_critical) | loadbalancer backend 4xx critical threshold in percentage | `number` | `10` | no | +| [elb\_backend\_4xx\_threshold\_warning](#input\_elb\_backend\_4xx\_threshold\_warning) | loadbalancer backend 4xx warning threshold in percentage | `number` | `5` | no | +| [elb\_backend\_4xx\_timeframe](#input\_elb\_backend\_4xx\_timeframe) | Monitor timeframe for ELB backend 4xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [elb\_backend\_5xx\_enabled](#input\_elb\_backend\_5xx\_enabled) | Flag to enable ELB backend 5xx errors monitor | `string` | `"true"` | no | +| [elb\_backend\_5xx\_extra\_tags](#input\_elb\_backend\_5xx\_extra\_tags) | Extra tags for ELB backend 5xx errors monitor | `list(string)` | `[]` | no | +| [elb\_backend\_5xx\_message](#input\_elb\_backend\_5xx\_message) | Custom message for ELB backend 5xx errors monitor | `string` | `""` | no | +| [elb\_backend\_5xx\_threshold\_critical](#input\_elb\_backend\_5xx\_threshold\_critical) | loadbalancer backend 5xx critical threshold in percentage | `number` | `10` | no | +| [elb\_backend\_5xx\_threshold\_warning](#input\_elb\_backend\_5xx\_threshold\_warning) | loadbalancer backend 5xx warning threshold in percentage | `number` | `5` | no | +| [elb\_backend\_5xx\_timeframe](#input\_elb\_backend\_5xx\_timeframe) | Monitor timeframe for ELB backend 5xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [elb\_backend\_latency\_critical](#input\_elb\_backend\_latency\_critical) | latency critical threshold in seconds | `number` | `3` | no | +| [elb\_backend\_latency\_enabled](#input\_elb\_backend\_latency\_enabled) | Flag to enable ELB backend latency monitor | `string` | `"true"` | no | +| [elb\_backend\_latency\_extra\_tags](#input\_elb\_backend\_latency\_extra\_tags) | Extra tags for ELB backend latency monitor | `list(string)` | `[]` | no | +| [elb\_backend\_latency\_message](#input\_elb\_backend\_latency\_message) | Custom message for ELB backend latency monitor | `string` | `""` | no | +| [elb\_backend\_latency\_time\_aggregator](#input\_elb\_backend\_latency\_time\_aggregator) | Monitor aggregator for ELB backend latency [available values: min, max or avg] | `string` | `"min"` | no | +| [elb\_backend\_latency\_timeframe](#input\_elb\_backend\_latency\_timeframe) | Monitor timeframe for ELB backend latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [elb\_backend\_latency\_warning](#input\_elb\_backend\_latency\_warning) | latency warning threshold in seconds | `number` | `1` | no | +| [elb\_no\_healthy\_instance\_enabled](#input\_elb\_no\_healthy\_instance\_enabled) | Flag to enable ELB no healty instance monitor | `string` | `"true"` | no | +| [elb\_no\_healthy\_instance\_extra\_tags](#input\_elb\_no\_healthy\_instance\_extra\_tags) | Extra tags for ELB no healty instance monitor | `list(string)` | `[]` | no | +| [elb\_no\_healthy\_instance\_message](#input\_elb\_no\_healthy\_instance\_message) | Custom message for ELB no healty instance monitor | `string` | `""` | no | +| [elb\_no\_healthy\_instance\_no\_data\_timeframe](#input\_elb\_no\_healthy\_instance\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [elb\_no\_healthy\_instance\_threshold\_warning](#input\_elb\_no\_healthy\_instance\_threshold\_warning) | ELB no healthy instances warning threshold in percentage | `number` | `100` | no | +| [elb\_no\_healthy\_instance\_time\_aggregator](#input\_elb\_no\_healthy\_instance\_time\_aggregator) | Monitor aggregator for ELB no healty instance [available values: min or max] | `string` | `"min"` | no | +| [elb\_no\_healthy\_instance\_timeframe](#input\_elb\_no\_healthy\_instance\_timeframe) | Monitor timeframe for ELB no healty instance [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [ELB\_backend\_latency\_id](#output\_ELB\_backend\_latency\_id) | id for monitor ELB\_backend\_latency | +| [ELB\_no\_healthy\_instances\_id](#output\_ELB\_no\_healthy\_instances\_id) | id for monitor ELB\_no\_healthy\_instances | +| [ELB\_too\_much\_4xx\_backend\_id](#output\_ELB\_too\_much\_4xx\_backend\_id) | id for monitor ELB\_too\_much\_4xx\_backend | +| [ELB\_too\_much\_4xx\_id](#output\_ELB\_too\_much\_4xx\_id) | id for monitor ELB\_too\_much\_4xx | +| [ELB\_too\_much\_5xx\_backend\_id](#output\_ELB\_too\_much\_5xx\_backend\_id) | id for monitor ELB\_too\_much\_5xx\_backend | +| [ELB\_too\_much\_5xx\_id](#output\_ELB\_too\_much\_5xx\_id) | id for monitor ELB\_too\_much\_5xx | +## Related documentation + +DataDog blog: [https://www.datadoghq.com/blog/monitor-application-load-balancer/](https://www.datadoghq.com/blog/monitor-application-load-balancer/) + +AWS ELB metrics documentation: [https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-cloudwatch-metrics.html](https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-cloudwatch-metrics.html) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elb/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elb/inputs.tf new file mode 100755 index 0000000..ce8c827 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elb/inputs.tf @@ -0,0 +1,270 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "elb_no_healthy_instance_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +## ELB + +variable "elb_no_healthy_instance_enabled" { + description = "Flag to enable ELB no healty instance monitor" + type = string + default = "true" +} + +variable "elb_no_healthy_instance_extra_tags" { + description = "Extra tags for ELB no healty instance monitor" + type = list(string) + default = [] +} + +variable "elb_no_healthy_instance_message" { + description = "Custom message for ELB no healty instance monitor" + type = string + default = "" +} + +variable "elb_no_healthy_instance_time_aggregator" { + description = "Monitor aggregator for ELB no healty instance [available values: min or max]" + type = string + default = "min" +} + +variable "elb_no_healthy_instance_timeframe" { + description = "Monitor timeframe for ELB no healty instance [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "elb_no_healthy_instance_threshold_warning" { + description = "ELB no healthy instances warning threshold in percentage" + default = 100 +} + +variable "elb_4xx_enabled" { + description = "Flag to enable ELB 4xx errors monitor" + type = string + default = "true" +} + +variable "elb_4xx_extra_tags" { + description = "Extra tags for ELB 4xx errors monitor" + type = list(string) + default = [] +} + +variable "elb_4xx_message" { + description = "Custom message for ELB 4xx errors monitor" + type = string + default = "" +} + +variable "elb_4xx_timeframe" { + description = "Monitor timeframe for ELB 4xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "elb_4xx_threshold_warning" { + description = "loadbalancer 4xx warning threshold in percentage" + default = 5 +} + +variable "elb_4xx_threshold_critical" { + description = "loadbalancer 4xx critical threshold in percentage" + default = 10 +} + +variable "elb_5xx_enabled" { + description = "Flag to enable ELB 5xx errors monitor" + type = string + default = "true" +} + +variable "elb_5xx_extra_tags" { + description = "Extra tags for ELB 5xx errors monitor" + type = list(string) + default = [] +} + +variable "elb_5xx_message" { + description = "Custom message for ELB 5xx errors monitor" + type = string + default = "" +} + +variable "elb_5xx_timeframe" { + description = "Monitor timeframe for ELB 5xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "elb_5xx_threshold_warning" { + description = "loadbalancer 5xx warning threshold in percentage" + default = 5 +} + +variable "elb_5xx_threshold_critical" { + description = "loadbalancer 5xx critical threshold in percentage" + default = 10 +} + +variable "elb_backend_4xx_enabled" { + description = "Flag to enable ELB backend 4xx errors monitor" + type = string + default = "true" +} + +variable "elb_backend_4xx_extra_tags" { + description = "Extra tags for ELB backend 4xx errors monitor" + type = list(string) + default = [] +} + +variable "elb_backend_4xx_message" { + description = "Custom message for ELB backend 4xx errors monitor" + type = string + default = "" +} + +variable "elb_backend_4xx_timeframe" { + description = "Monitor timeframe for ELB backend 4xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "elb_backend_4xx_threshold_warning" { + description = "loadbalancer backend 4xx warning threshold in percentage" + default = 5 +} + +variable "elb_backend_4xx_threshold_critical" { + description = "loadbalancer backend 4xx critical threshold in percentage" + default = 10 +} + +variable "elb_backend_5xx_enabled" { + description = "Flag to enable ELB backend 5xx errors monitor" + type = string + default = "true" +} + +variable "elb_backend_5xx_extra_tags" { + description = "Extra tags for ELB backend 5xx errors monitor" + type = list(string) + default = [] +} + +variable "elb_backend_5xx_message" { + description = "Custom message for ELB backend 5xx errors monitor" + type = string + default = "" +} + +variable "elb_backend_5xx_timeframe" { + description = "Monitor timeframe for ELB backend 5xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "elb_backend_5xx_threshold_warning" { + description = "loadbalancer backend 5xx warning threshold in percentage" + default = 5 +} + +variable "elb_backend_5xx_threshold_critical" { + description = "loadbalancer backend 5xx critical threshold in percentage" + default = 10 +} + +variable "elb_backend_latency_enabled" { + description = "Flag to enable ELB backend latency monitor" + type = string + default = "true" +} + +variable "elb_backend_latency_extra_tags" { + description = "Extra tags for ELB backend latency monitor" + type = list(string) + default = [] +} + +variable "elb_backend_latency_message" { + description = "Custom message for ELB backend latency monitor" + type = string + default = "" +} + +variable "elb_backend_latency_time_aggregator" { + description = "Monitor aggregator for ELB backend latency [available values: min, max or avg]" + type = string + default = "min" +} + +variable "elb_backend_latency_timeframe" { + description = "Monitor timeframe for ELB backend latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "elb_backend_latency_warning" { + description = "latency warning threshold in seconds" + default = 1 +} + +variable "elb_backend_latency_critical" { + description = "latency critical threshold in seconds" + default = 3 +} + +variable "artificial_requests_count" { + default = 5 + description = "Number of false requests used to mitigate false positive in case of low trafic" +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elb/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elb/modules.tf new file mode 100755 index 0000000..9d396f6 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elb/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "aws_elb" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elb/monitors-elb.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elb/monitors-elb.tf new file mode 100755 index 0000000..c936852 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elb/monitors-elb.tf @@ -0,0 +1,187 @@ +resource "datadog_monitor" "ELB_no_healthy_instances" { + count = var.elb_no_healthy_instance_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ELB healthy instances {{#is_alert}}is at 0{{/is_alert}}{{#is_warning}}is at {{value}}%%{{/is_warning}}" + message = coalesce(var.elb_no_healthy_instance_message, var.message) + type = "query alert" + + query = < ${var.elb_4xx_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.elb_4xx_threshold_warning + critical = var.elb_4xx_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elb", "team:claranet", "created-by:terraform"], var.elb_4xx_extra_tags) +} + +resource "datadog_monitor" "ELB_too_much_5xx" { + count = var.elb_5xx_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ELB 5xx errors too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.elb_5xx_message, var.message) + type = "query alert" + + query = < ${var.elb_5xx_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.elb_5xx_threshold_warning + critical = var.elb_5xx_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elb", "team:claranet", "created-by:terraform"], var.elb_5xx_extra_tags) +} + +resource "datadog_monitor" "ELB_too_much_4xx_backend" { + count = var.elb_backend_4xx_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ELB backend 4xx errors too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.elb_backend_4xx_message, var.message) + type = "query alert" + + query = < ${var.elb_backend_4xx_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.elb_backend_4xx_threshold_warning + critical = var.elb_backend_4xx_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elb", "team:claranet", "created-by:terraform"], var.elb_backend_4xx_extra_tags) +} + +resource "datadog_monitor" "ELB_too_much_5xx_backend" { + count = var.elb_backend_5xx_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ELB backend 5xx errors too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.elb_backend_5xx_message, var.message) + type = "query alert" + + query = < ${var.elb_backend_5xx_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.elb_backend_5xx_threshold_warning + critical = var.elb_backend_5xx_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elb", "team:claranet", "created-by:terraform"], var.elb_backend_5xx_extra_tags) +} + +resource "datadog_monitor" "ELB_backend_latency" { + count = var.elb_backend_latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ELB latency too high {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + message = coalesce(var.elb_backend_latency_message, var.message) + type = "query alert" + + query = < ${var.elb_backend_latency_critical} +EOQ + + monitor_thresholds { + warning = var.elb_backend_latency_warning + critical = var.elb_backend_latency_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elb", "team:claranet", "created-by:terraform"], var.elb_backend_latency_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elb/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elb/outputs.tf new file mode 100755 index 0000000..19c1dd3 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elb/outputs.tf @@ -0,0 +1,30 @@ +output "ELB_backend_latency_id" { + description = "id for monitor ELB_backend_latency" + value = datadog_monitor.ELB_backend_latency.*.id +} + +output "ELB_no_healthy_instances_id" { + description = "id for monitor ELB_no_healthy_instances" + value = datadog_monitor.ELB_no_healthy_instances.*.id +} + +output "ELB_too_much_4xx_id" { + description = "id for monitor ELB_too_much_4xx" + value = datadog_monitor.ELB_too_much_4xx.*.id +} + +output "ELB_too_much_4xx_backend_id" { + description = "id for monitor ELB_too_much_4xx_backend" + value = datadog_monitor.ELB_too_much_4xx_backend.*.id +} + +output "ELB_too_much_5xx_id" { + description = "id for monitor ELB_too_much_5xx" + value = datadog_monitor.ELB_too_much_5xx.*.id +} + +output "ELB_too_much_5xx_backend_id" { + description = "id for monitor ELB_too_much_5xx_backend" + value = datadog_monitor.ELB_too_much_5xx_backend.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elb/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elb/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/elb/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/kinesis-firehose/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/kinesis-firehose/README.md new file mode 100755 index 0000000..ef2d55c --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/kinesis-firehose/README.md @@ -0,0 +1,75 @@ +# CLOUD AWS KINESIS-FIREHOSE DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-kinesis-firehose" { + source = "claranet/monitors/datadog//cloud/aws/kinesis-firehose" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Kinesis Firehose No incoming records + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.firehose_incoming_records](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [firehose\_incoming\_records\_no\_data\_timeframe](#input\_firehose\_incoming\_records\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `30` | no | +| [incoming\_records\_enabled](#input\_incoming\_records\_enabled) | Flag to enable Kinesis Firehorse incoming records monitor | `string` | `"true"` | no | +| [incoming\_records\_extra\_tags](#input\_incoming\_records\_extra\_tags) | Extra tags for Kinesis Firehorse incoming records monitor | `list(string)` | `[]` | no | +| [incoming\_records\_message](#input\_incoming\_records\_message) | Custom message for Kinesis Firehorse incoming records monitor | `string` | `""` | no | +| [incoming\_records\_timeframe](#input\_incoming\_records\_timeframe) | Monitor timeframe for incoming records metrics evaluation [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [firehose\_incoming\_records\_id](#output\_firehose\_incoming\_records\_id) | id for monitor firehose\_incoming\_records | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/amazon_firehose/](https://docs.datadoghq.com/integrations/amazon_firehose/) + +AWS Kinesis Firehose metrics documentation: [https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/akf-metricscollected.html](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/akf-metricscollected.html) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/kinesis-firehose/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/kinesis-firehose/inputs.tf new file mode 100755 index 0000000..df1bc09 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/kinesis-firehose/inputs.tf @@ -0,0 +1,77 @@ +# Global Terraform +variable "environment" { + description = "Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "firehose_incoming_records_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 30 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Kinesis-Firehose + +variable "incoming_records_enabled" { + description = "Flag to enable Kinesis Firehorse incoming records monitor" + type = string + default = "true" +} + +variable "incoming_records_extra_tags" { + description = "Extra tags for Kinesis Firehorse incoming records monitor" + type = list(string) + default = [] +} + +variable "incoming_records_message" { + description = "Custom message for Kinesis Firehorse incoming records monitor" + type = string + default = "" +} + +variable "incoming_records_timeframe" { + description = "Monitor timeframe for incoming records metrics evaluation [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + default = "last_15m" +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/kinesis-firehose/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/kinesis-firehose/modules.tf new file mode 100755 index 0000000..f9113f5 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/kinesis-firehose/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "aws_kinesis-firehose" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/kinesis-firehose/monitors-kinesis-firehose.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/kinesis-firehose/monitors-kinesis-firehose.tf new file mode 100755 index 0000000..e0fb7a0 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/kinesis-firehose/monitors-kinesis-firehose.tf @@ -0,0 +1,31 @@ +### Kinesis Firehose Incoming records ### +resource "datadog_monitor" "firehose_incoming_records" { + count = var.incoming_records_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Kinesis Firehose No incoming records" + message = coalesce(var.incoming_records_message, var.message) + type = "query alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.invocations](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.pct_errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.throttles](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [errors\_enabled](#input\_errors\_enabled) | Flag to enable Errors monitor | `string` | `"false"` | no | +| [errors\_extra\_tags](#input\_errors\_extra\_tags) | Extra tags for Errors monitor | `list(string)` | `[]` | no | +| [errors\_message](#input\_errors\_message) | Custom message for Errors monitor | `string` | `""` | no | +| [errors\_threshold\_critical](#input\_errors\_threshold\_critical) | Alerting threshold in milliseconds | `number` | `3` | no | +| [errors\_threshold\_warning](#input\_errors\_threshold\_warning) | Warning threshold in milliseconds | `number` | `1` | no | +| [errors\_time\_aggregator](#input\_errors\_time\_aggregator) | Monitor aggregator for Errors [available values: min, max or avg] | `string` | `"sum"` | no | +| [errors\_timeframe](#input\_errors\_timeframe) | Monitor timeframe for Errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1h"` | no | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [invocations\_enabled](#input\_invocations\_enabled) | Flag to enable Invocations monitor | `string` | `"false"` | no | +| [invocations\_extra\_tags](#input\_invocations\_extra\_tags) | Extra tags for Invocations monitor | `list(string)` | `[]` | no | +| [invocations\_message](#input\_invocations\_message) | Custom message for Invocations monitor | `string` | `""` | no | +| [invocations\_no\_data\_timeframe](#input\_invocations\_no\_data\_timeframe) | Timeframe to check before alerting on no data in minutes | `number` | `120` | no | +| [invocations\_threshold\_critical](#input\_invocations\_threshold\_critical) | Alerting threshold in number of invocations | `number` | `1` | no | +| [invocations\_threshold\_warning](#input\_invocations\_threshold\_warning) | Warning threshold in number of invocations | `number` | `2` | no | +| [invocations\_time\_aggregator](#input\_invocations\_time\_aggregator) | Monitor aggregator for Invocations [available values: min, max or avg] | `string` | `"sum"` | no | +| [invocations\_timeframe](#input\_invocations\_timeframe) | Monitor timeframe for Invocations [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_30m"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [pct\_errors\_enabled](#input\_pct\_errors\_enabled) | Flag to enable Percentage of errors monitor | `string` | `"true"` | no | +| [pct\_errors\_extra\_tags](#input\_pct\_errors\_extra\_tags) | Extra tags for Percentage of errors monitor | `list(string)` | `[]` | no | +| [pct\_errors\_message](#input\_pct\_errors\_message) | Custom message for Percentage of errors monitor | `string` | `""` | no | +| [pct\_errors\_threshold\_critical](#input\_pct\_errors\_threshold\_critical) | Alerting threshold in percentage | `number` | `30` | no | +| [pct\_errors\_threshold\_warning](#input\_pct\_errors\_threshold\_warning) | Warning threshold in percentage | `number` | `20` | no | +| [pct\_errors\_time\_aggregator](#input\_pct\_errors\_time\_aggregator) | Monitor aggregator for Percentage of errors [available values: min, max or avg] | `string` | `"sum"` | no | +| [pct\_errors\_timeframe](#input\_pct\_errors\_timeframe) | Monitor timeframe for Percentage of errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1h"` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [throttles\_enabled](#input\_throttles\_enabled) | Flag to enable Throttles monitor | `string` | `"true"` | no | +| [throttles\_extra\_tags](#input\_throttles\_extra\_tags) | Extra tags for Throttles monitor | `list(string)` | `[]` | no | +| [throttles\_message](#input\_throttles\_message) | Custom message for Throttles monitor | `string` | `""` | no | +| [throttles\_threshold\_critical](#input\_throttles\_threshold\_critical) | Alerting threshold in number of throttles | `number` | `3` | no | +| [throttles\_threshold\_warning](#input\_throttles\_threshold\_warning) | Warning threshold in number of throttles | `number` | `1` | no | +| [throttles\_time\_aggregator](#input\_throttles\_time\_aggregator) | Monitor aggregator for Throttles [available values: min, max or avg] | `string` | `"sum"` | no | +| [throttles\_timeframe](#input\_throttles\_timeframe) | Monitor timeframe for Throttles [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1h"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [errors\_id](#output\_errors\_id) | id for monitor errors | +| [invocations\_id](#output\_invocations\_id) | id for monitor invocations | +| [pct\_errors\_id](#output\_pct\_errors\_id) | id for monitor pct\_errors | +| [throttles\_id](#output\_throttles\_id) | id for monitor throttles | +## Related documentation +* [Datadog Documentation](https://docs.datadoghq.com/integrations/amazon_lambda/) +* [Service documentation](https://docs.aws.amazon.com/lambda/index.html) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/lambda/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/lambda/inputs.tf new file mode 100755 index 0000000..a8b9a24 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/lambda/inputs.tf @@ -0,0 +1,216 @@ +# Datadog global variables + +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# Datadog monitors variables + +# Percentage of errors +variable "pct_errors_enabled" { + description = "Flag to enable Percentage of errors monitor" + type = string + default = "true" +} + +variable "pct_errors_extra_tags" { + description = "Extra tags for Percentage of errors monitor" + type = list(string) + default = [] +} + +variable "pct_errors_message" { + description = "Custom message for Percentage of errors monitor" + type = string + default = "" +} + +variable "pct_errors_time_aggregator" { + description = "Monitor aggregator for Percentage of errors [available values: min, max or avg]" + type = string + default = "sum" +} + +variable "pct_errors_timeframe" { + description = "Monitor timeframe for Percentage of errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1h" +} + +variable "pct_errors_threshold_critical" { + default = 30 + description = "Alerting threshold in percentage" +} + +variable "pct_errors_threshold_warning" { + default = 20 + description = "Warning threshold in percentage" +} + +# Errors count +variable "errors_enabled" { + description = "Flag to enable Errors monitor" + type = string + default = "false" +} + +variable "errors_extra_tags" { + description = "Extra tags for Errors monitor" + type = list(string) + default = [] +} + +variable "errors_message" { + description = "Custom message for Errors monitor" + type = string + default = "" +} + +variable "errors_time_aggregator" { + description = "Monitor aggregator for Errors [available values: min, max or avg]" + type = string + default = "sum" +} + +variable "errors_timeframe" { + description = "Monitor timeframe for Errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1h" +} + +variable "errors_threshold_critical" { + default = 3 + description = "Alerting threshold in milliseconds" +} + +variable "errors_threshold_warning" { + default = 1 + description = "Warning threshold in milliseconds" +} + +# Throttles count +variable "throttles_enabled" { + description = "Flag to enable Throttles monitor" + type = string + default = "true" +} + +variable "throttles_extra_tags" { + description = "Extra tags for Throttles monitor" + type = list(string) + default = [] +} + +variable "throttles_message" { + description = "Custom message for Throttles monitor" + type = string + default = "" +} + +variable "throttles_time_aggregator" { + description = "Monitor aggregator for Throttles [available values: min, max or avg]" + type = string + default = "sum" +} + +variable "throttles_timeframe" { + description = "Monitor timeframe for Throttles [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1h" +} + +variable "throttles_threshold_critical" { + default = 3 + description = "Alerting threshold in number of throttles" +} + +variable "throttles_threshold_warning" { + default = 1 + description = "Warning threshold in number of throttles" +} + +# Invocations +variable "invocations_enabled" { + description = "Flag to enable Invocations monitor" + type = string + default = "false" +} + +variable "invocations_extra_tags" { + description = "Extra tags for Invocations monitor" + type = list(string) + default = [] +} + +variable "invocations_message" { + description = "Custom message for Invocations monitor" + type = string + default = "" +} + +variable "invocations_time_aggregator" { + description = "Monitor aggregator for Invocations [available values: min, max or avg]" + type = string + default = "sum" +} + +variable "invocations_timeframe" { + description = "Monitor timeframe for Invocations [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_30m" +} + +variable "invocations_threshold_critical" { + default = 1 + description = "Alerting threshold in number of invocations" +} + +variable "invocations_threshold_warning" { + default = 2 + description = "Warning threshold in number of invocations" +} + +variable "invocations_no_data_timeframe" { + default = 120 + description = "Timeframe to check before alerting on no data in minutes" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/lambda/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/lambda/modules.tf new file mode 100755 index 0000000..161aebe --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/lambda/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "aws_lambda" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} \ No newline at end of file diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/lambda/monitors-lambda.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/lambda/monitors-lambda.tf new file mode 100755 index 0000000..53f0616 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/lambda/monitors-lambda.tf @@ -0,0 +1,134 @@ +# Errors Percent +resource "datadog_monitor" "pct_errors" { + count = var.pct_errors_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Lambda Percentage of errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + type = "metric alert" + message = coalesce(var.pct_errors_message, var.message) + + query = < ${var.pct_errors_threshold_critical} + EOQ + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + + monitor_thresholds { + critical = var.pct_errors_threshold_critical + warning = var.pct_errors_threshold_warning + } + + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:lambda", "team:claranet", "created-by:terraform"], var.pct_errors_extra_tags) +} + +# Errors Absolute Value +resource "datadog_monitor" "errors" { + count = var.errors_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Lambda Number of errors {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + type = "metric alert" + message = coalesce(var.errors_message, var.message) + + query = < ${var.errors_threshold_critical} + EOQ + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + + monitor_thresholds { + critical = var.errors_threshold_critical + warning = var.errors_threshold_warning + } + + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:lambda", "team:claranet", "created-by:terraform"], var.errors_extra_tags) +} + +# Throttles +resource "datadog_monitor" "throttles" { + count = var.throttles_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Lambda Invocations throttled due to concurrent limit reached {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + type = "metric alert" + message = coalesce(var.throttles_message, var.message) + + query = < ${var.throttles_threshold_critical} + EOQ + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + + monitor_thresholds { + critical = var.throttles_threshold_critical + warning = var.throttles_threshold_warning + } + + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:lambda", "team:claranet", "created-by:terraform"], var.throttles_extra_tags) +} + +# INVOCATIONS +resource "datadog_monitor" "invocations" { + count = var.invocations_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Lambda Number of invocations {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + type = "metric alert" + message = coalesce(var.invocations_message, var.message) + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.NLB_no_healthy_instances](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [nlb\_no\_healthy\_instances\_enabled](#input\_nlb\_no\_healthy\_instances\_enabled) | Flag to enable NLB no healthy instances monitor | `string` | `"true"` | no | +| [nlb\_no\_healthy\_instances\_extra\_tags](#input\_nlb\_no\_healthy\_instances\_extra\_tags) | Extra tags for NLB no healthy instances monitor | `list(string)` | `[]` | no | +| [nlb\_no\_healthy\_instances\_message](#input\_nlb\_no\_healthy\_instances\_message) | Custom message for NLB no healthy instances monitor | `string` | `""` | no | +| [nlb\_no\_healthy\_instances\_no\_data\_timeframe](#input\_nlb\_no\_healthy\_instances\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [nlb\_no\_healthy\_instances\_threshold\_warning](#input\_nlb\_no\_healthy\_instances\_threshold\_warning) | NLB no healthy instances warning threshold in percentage | `number` | `100` | no | +| [nlb\_no\_healthy\_instances\_time\_aggregator](#input\_nlb\_no\_healthy\_instances\_time\_aggregator) | Monitor aggregator for NLB no healthy instances [available values: min, max or avg] | `string` | `"min"` | no | +| [nlb\_no\_healthy\_instances\_timeframe](#input\_nlb\_no\_healthy\_instances\_timeframe) | Monitor timeframe for NLB no healthy instances [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [NLB\_no\_healthy\_instances\_id](#output\_NLB\_no\_healthy\_instances\_id) | id for monitor NLB\_no\_healthy\_instances | +## Related documentation + +DataDog blog: [https://www.datadoghq.com/blog/monitor-aws-network-load-balancer/](https://www.datadoghq.com/blog/monitor-aws-network-load-balancer/) + +AWS NLB metrics documentation: [https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-cloudwatch-metrics.html](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-cloudwatch-metrics.html) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/nlb/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/nlb/inputs.tf new file mode 100755 index 0000000..3c93503 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/nlb/inputs.tf @@ -0,0 +1,88 @@ +# Datadog global variables + +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "nlb_no_healthy_instances_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# Datadog monitors variables + +variable "nlb_no_healthy_instances_enabled" { + description = "Flag to enable NLB no healthy instances monitor" + type = string + default = "true" +} + +variable "nlb_no_healthy_instances_extra_tags" { + description = "Extra tags for NLB no healthy instances monitor" + type = list(string) + default = [] +} + +variable "nlb_no_healthy_instances_message" { + description = "Custom message for NLB no healthy instances monitor" + type = string + default = "" +} + +variable "nlb_no_healthy_instances_time_aggregator" { + description = "Monitor aggregator for NLB no healthy instances [available values: min, max or avg]" + type = string + default = "min" +} + +variable "nlb_no_healthy_instances_timeframe" { + description = "Monitor timeframe for NLB no healthy instances [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "nlb_no_healthy_instances_threshold_warning" { + description = "NLB no healthy instances warning threshold in percentage" + default = 100 +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/nlb/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/nlb/modules.tf new file mode 100755 index 0000000..4899a5d --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/nlb/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "aws_nlb" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/nlb/monitors-nlb.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/nlb/monitors-nlb.tf new file mode 100755 index 0000000..2de3037 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/nlb/monitors-nlb.tf @@ -0,0 +1,31 @@ +resource "datadog_monitor" "NLB_no_healthy_instances" { + count = var.nlb_no_healthy_instances_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] NLB healthy instances {{#is_alert}}is at 0{{/is_alert}}{{#is_warning}}is at {{value}}%%{{/is_warning}}" + message = coalesce(var.nlb_no_healthy_instances_message, var.message) + type = "query alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.rds_aurora_mysql_replica_lag](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [aurora\_replicalag\_enabled](#input\_aurora\_replicalag\_enabled) | Flag to enable RDS Aurora replica lag monitor | `string` | `"true"` | no | +| [aurora\_replicalag\_extra\_tags](#input\_aurora\_replicalag\_extra\_tags) | Extra tags for RDS Aurora replica lag monitor | `list(string)` | `[]` | no | +| [aurora\_replicalag\_message](#input\_aurora\_replicalag\_message) | Custom message for RDS Aurora replica lag monitor | `string` | `""` | no | +| [aurora\_replicalag\_threshold\_critical](#input\_aurora\_replicalag\_threshold\_critical) | Aurora replica lag in milliseconds (critical threshold) | `string` | `"200"` | no | +| [aurora\_replicalag\_threshold\_warning](#input\_aurora\_replicalag\_threshold\_warning) | Aurora replica lag in milliseconds (warning threshold) | `string` | `"100"` | no | +| [aurora\_replicalag\_time\_aggregator](#input\_aurora\_replicalag\_time\_aggregator) | Monitor aggregator for RDS Aurora replica lag [available values: min, max or avg] | `string` | `"min"` | no | +| [aurora\_replicalag\_timeframe](#input\_aurora\_replicalag\_timeframe) | Monitor timeframe for RDS Aurora replica lag monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [rds\_aurora\_mysql\_replica\_lag\_no\_data\_timeframe](#input\_rds\_aurora\_mysql\_replica\_lag\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [rds\_aurora\_mysql\_replica\_lag\_id](#output\_rds\_aurora\_mysql\_replica\_lag\_id) | id for monitor rds\_aurora\_mysql\_replica\_lag | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/amazon_rds/](https://docs.datadoghq.com/integrations/amazon_rds/) + +AWS RDS Instance metrics documentation: [https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/MonitoringOverview.html#monitoring-cloudwatch](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/MonitoringOverview.html#monitoring-cloudwatch) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/mysql/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/mysql/inputs.tf new file mode 100755 index 0000000..3425832 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/mysql/inputs.tf @@ -0,0 +1,93 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "rds_aurora_mysql_replica_lag_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# AWS RDS Aurora instance specific + +variable "aurora_replicalag_enabled" { + description = "Flag to enable RDS Aurora replica lag monitor" + type = string + default = "true" +} + +variable "aurora_replicalag_extra_tags" { + description = "Extra tags for RDS Aurora replica lag monitor" + type = list(string) + default = [] +} + +variable "aurora_replicalag_message" { + description = "Custom message for RDS Aurora replica lag monitor" + type = string + default = "" +} + +variable "aurora_replicalag_time_aggregator" { + description = "Monitor aggregator for RDS Aurora replica lag [available values: min, max or avg]" + type = string + default = "min" +} + +variable "aurora_replicalag_timeframe" { + description = "Monitor timeframe for RDS Aurora replica lag monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "aurora_replicalag_threshold_warning" { + description = "Aurora replica lag in milliseconds (warning threshold)" + default = "100" +} + +variable "aurora_replicalag_threshold_critical" { + description = "Aurora replica lag in milliseconds (critical threshold)" + default = "200" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/mysql/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/mysql/modules.tf new file mode 100755 index 0000000..a5459e6 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/mysql/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../../../common/filter-tags" + + environment = var.environment + resource = "aws_rds" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/mysql/monitors-rds-aurora-mysql.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/mysql/monitors-rds-aurora-mysql.tf new file mode 100755 index 0000000..9542979 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/mysql/monitors-rds-aurora-mysql.tf @@ -0,0 +1,30 @@ +### RDS Aurora Mysql Replica Lag monitor ### +resource "datadog_monitor" "rds_aurora_mysql_replica_lag" { + count = var.aurora_replicalag_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] RDS Aurora Mysql replica lag {{#is_alert}}{{{comparator}}} {{threshold}} ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.aurora_replicalag_message, var.message) + type = "query alert" + + query = < ${var.aurora_replicalag_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.aurora_replicalag_threshold_warning + critical = var.aurora_replicalag_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = var.notify_no_data + no_data_timeframe = var.rds_aurora_mysql_replica_lag_no_data_timeframe + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:rds-aurora-mysql", "team:claranet", "created-by:terraform"], var.aurora_replicalag_extra_tags) +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/mysql/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/mysql/outputs.tf new file mode 100755 index 0000000..f94f46d --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/mysql/outputs.tf @@ -0,0 +1,5 @@ +output "rds_aurora_mysql_replica_lag_id" { + description = "id for monitor rds_aurora_mysql_replica_lag" + value = datadog_monitor.rds_aurora_mysql_replica_lag.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/mysql/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/mysql/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/mysql/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/postgresql/MANIFEST.txt b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/postgresql/MANIFEST.txt new file mode 100755 index 0000000..3d83252 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/postgresql/MANIFEST.txt @@ -0,0 +1 @@ +cloud-aws diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/postgresql/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/postgresql/README.md new file mode 100755 index 0000000..7397fae --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/postgresql/README.md @@ -0,0 +1,78 @@ +# CLOUD AWS RDS AURORA POSTGRESQL DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-rds-aurora-postgresql" { + source = "claranet/monitors/datadog//cloud/aws/rds/aurora/postgresql" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- RDS Aurora PostgreSQL replica lag + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.rds_aurora_postgresql_replica_lag](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [aurora\_replicalag\_enabled](#input\_aurora\_replicalag\_enabled) | Flag to enable RDS Aurora replica lag monitor | `string` | `"true"` | no | +| [aurora\_replicalag\_extra\_tags](#input\_aurora\_replicalag\_extra\_tags) | Extra tags for RDS Aurora replica lag monitor | `list(string)` | `[]` | no | +| [aurora\_replicalag\_message](#input\_aurora\_replicalag\_message) | Custom message for RDS Aurora replica lag monitor | `string` | `""` | no | +| [aurora\_replicalag\_threshold\_critical](#input\_aurora\_replicalag\_threshold\_critical) | Aurora replica lag in milliseconds (critical threshold) | `string` | `"200"` | no | +| [aurora\_replicalag\_threshold\_warning](#input\_aurora\_replicalag\_threshold\_warning) | Aurora replica lag in milliseconds (warning threshold) | `string` | `"100"` | no | +| [aurora\_replicalag\_time\_aggregator](#input\_aurora\_replicalag\_time\_aggregator) | Monitor aggregator for RDS Aurora replica lag [available values: min, max or avg] | `string` | `"min"` | no | +| [aurora\_replicalag\_timeframe](#input\_aurora\_replicalag\_timeframe) | Monitor timeframe for RDS Aurora replica lag monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [rds\_aurora\_postgresql\_replica\_lag\_no\_data\_timeframe](#input\_rds\_aurora\_postgresql\_replica\_lag\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [rds\_aurora\_postgresql\_replica\_lag\_id](#output\_rds\_aurora\_postgresql\_replica\_lag\_id) | id for monitor rds\_aurora\_postgresql\_replica\_lag | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/amazon_rds/](https://docs.datadoghq.com/integrations/amazon_rds/) + +AWS RDS Instance metrics documentation: [https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/MonitoringOverview.html#monitoring-cloudwatch](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/MonitoringOverview.html#monitoring-cloudwatch) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/postgresql/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/postgresql/inputs.tf new file mode 100755 index 0000000..991a67d --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/postgresql/inputs.tf @@ -0,0 +1,93 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "rds_aurora_postgresql_replica_lag_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# AWS RDS Aurora instance specific + +variable "aurora_replicalag_enabled" { + description = "Flag to enable RDS Aurora replica lag monitor" + type = string + default = "true" +} + +variable "aurora_replicalag_extra_tags" { + description = "Extra tags for RDS Aurora replica lag monitor" + type = list(string) + default = [] +} + +variable "aurora_replicalag_message" { + description = "Custom message for RDS Aurora replica lag monitor" + type = string + default = "" +} + +variable "aurora_replicalag_time_aggregator" { + description = "Monitor aggregator for RDS Aurora replica lag [available values: min, max or avg]" + type = string + default = "min" +} + +variable "aurora_replicalag_timeframe" { + description = "Monitor timeframe for RDS Aurora replica lag monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "aurora_replicalag_threshold_warning" { + description = "Aurora replica lag in milliseconds (warning threshold)" + default = "100" +} + +variable "aurora_replicalag_threshold_critical" { + description = "Aurora replica lag in milliseconds (critical threshold)" + default = "200" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/postgresql/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/postgresql/modules.tf new file mode 100755 index 0000000..a5459e6 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/postgresql/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../../../common/filter-tags" + + environment = var.environment + resource = "aws_rds" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/postgresql/monitors-rds-aurora-postgresql.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/postgresql/monitors-rds-aurora-postgresql.tf new file mode 100755 index 0000000..7b43be3 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/postgresql/monitors-rds-aurora-postgresql.tf @@ -0,0 +1,30 @@ +### RDS Aurora Postgresql Replica Lag monitor ### +resource "datadog_monitor" "rds_aurora_postgresql_replica_lag" { + count = var.aurora_replicalag_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] RDS Aurora PostgreSQL replica lag {{#is_alert}}{{{comparator}}} {{threshold}} ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.aurora_replicalag_message, var.message) + type = "query alert" + + query = < ${var.aurora_replicalag_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.aurora_replicalag_threshold_warning + critical = var.aurora_replicalag_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = var.notify_no_data + no_data_timeframe = var.rds_aurora_postgresql_replica_lag_no_data_timeframe + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:rds-aurora-postgresql", "team:claranet", "created-by:terraform"], var.aurora_replicalag_extra_tags) +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/postgresql/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/postgresql/outputs.tf new file mode 100755 index 0000000..118d6bb --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/postgresql/outputs.tf @@ -0,0 +1,5 @@ +output "rds_aurora_postgresql_replica_lag_id" { + description = "id for monitor rds_aurora_postgresql_replica_lag" + value = datadog_monitor.rds_aurora_postgresql_replica_lag.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/postgresql/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/postgresql/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/aurora/postgresql/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/common/MANIFEST.txt b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/common/MANIFEST.txt new file mode 100755 index 0000000..3d83252 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/common/MANIFEST.txt @@ -0,0 +1 @@ +cloud-aws diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/common/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/common/README.md new file mode 100755 index 0000000..daefac8 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/common/README.md @@ -0,0 +1,98 @@ +# CLOUD AWS RDS COMMON DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-rds-common" { + source = "claranet/monitors/datadog//cloud/aws/rds/common" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- RDS instance CPU high +- RDS instance free space +- RDS replica lag + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.rds_cpu_90_15min](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.rds_free_space_low](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.rds_replica_lag](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_enabled](#input\_cpu\_enabled) | Flag to enable RDS CPU usage monitor | `string` | `"true"` | no | +| [cpu\_extra\_tags](#input\_cpu\_extra\_tags) | Extra tags for RDS CPU usage monitor | `list(string)` | `[]` | no | +| [cpu\_message](#input\_cpu\_message) | Custom message for RDS CPU usage monitor | `string` | `""` | no | +| [cpu\_threshold\_critical](#input\_cpu\_threshold\_critical) | CPU usage in percent (critical threshold) | `string` | `"90"` | no | +| [cpu\_threshold\_warning](#input\_cpu\_threshold\_warning) | CPU usage in percent (warning threshold) | `string` | `"80"` | no | +| [cpu\_time\_aggregator](#input\_cpu\_time\_aggregator) | Monitor aggregator for RDS CPU usage [available values: min, max or avg] | `string` | `"min"` | no | +| [cpu\_timeframe](#input\_cpu\_timeframe) | Monitor timeframe for RDS CPU usage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [diskspace\_enabled](#input\_diskspace\_enabled) | Flag to enable RDS free diskspace monitor | `string` | `"true"` | no | +| [diskspace\_extra\_tags](#input\_diskspace\_extra\_tags) | Extra tags for RDS free diskspace monitor | `list(string)` | `[]` | no | +| [diskspace\_message](#input\_diskspace\_message) | Custom message for RDS free diskspace monitor | `string` | `""` | no | +| [diskspace\_threshold\_critical](#input\_diskspace\_threshold\_critical) | Disk free space in percent (critical threshold) | `string` | `"10"` | no | +| [diskspace\_threshold\_warning](#input\_diskspace\_threshold\_warning) | Disk free space in percent (warning threshold) | `string` | `"20"` | no | +| [diskspace\_time\_aggregator](#input\_diskspace\_time\_aggregator) | Monitor aggregator for RDS free diskspace [available values: min, max or avg] | `string` | `"min"` | no | +| [diskspace\_timeframe](#input\_diskspace\_timeframe) | Monitor timeframe for RDS free diskspace [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [rds\_free\_space\_low\_no\_data\_timeframe](#input\_rds\_free\_space\_low\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `30` | no | +| [replicalag\_enabled](#input\_replicalag\_enabled) | Flag to enable RDS replica lag monitor | `string` | `"true"` | no | +| [replicalag\_extra\_tags](#input\_replicalag\_extra\_tags) | Extra tags for RDS replica lag monitor | `list(string)` | `[]` | no | +| [replicalag\_message](#input\_replicalag\_message) | Custom message for RDS replica lag monitor | `string` | `""` | no | +| [replicalag\_threshold\_critical](#input\_replicalag\_threshold\_critical) | replica lag in seconds (critical threshold) | `string` | `"300"` | no | +| [replicalag\_threshold\_warning](#input\_replicalag\_threshold\_warning) | replica lag in seconds (warning threshold) | `string` | `"200"` | no | +| [replicalag\_time\_aggregator](#input\_replicalag\_time\_aggregator) | Monitor aggregator for RDS replica lag [available values: min, max or avg] | `string` | `"min"` | no | +| [replicalag\_timeframe](#input\_replicalag\_timeframe) | Monitor timeframe for RDS replica lag monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [rds\_cpu\_90\_15min\_id](#output\_rds\_cpu\_90\_15min\_id) | id for monitor rds\_cpu\_90\_15min | +| [rds\_free\_space\_low\_id](#output\_rds\_free\_space\_low\_id) | id for monitor rds\_free\_space\_low | +| [rds\_replica\_lag\_id](#output\_rds\_replica\_lag\_id) | id for monitor rds\_replica\_lag | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/amazon_rds/](https://docs.datadoghq.com/integrations/amazon_rds/) + +AWS RDS Instance metrics documentation: [https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/MonitoringOverview.html#monitoring-cloudwatch](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/MonitoringOverview.html#monitoring-cloudwatch) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/common/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/common/inputs.tf new file mode 100755 index 0000000..634d5d9 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/common/inputs.tf @@ -0,0 +1,173 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "rds_free_space_low_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 30 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# AWS RDS instance specific + +variable "cpu_enabled" { + description = "Flag to enable RDS CPU usage monitor" + type = string + default = "true" +} + +variable "cpu_extra_tags" { + description = "Extra tags for RDS CPU usage monitor" + type = list(string) + default = [] +} + +variable "cpu_message" { + description = "Custom message for RDS CPU usage monitor" + type = string + default = "" +} + +variable "cpu_time_aggregator" { + description = "Monitor aggregator for RDS CPU usage [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cpu_timeframe" { + description = "Monitor timeframe for RDS CPU usage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "cpu_threshold_warning" { + description = "CPU usage in percent (warning threshold)" + default = "80" +} + +variable "cpu_threshold_critical" { + description = "CPU usage in percent (critical threshold)" + default = "90" +} + +variable "diskspace_enabled" { + description = "Flag to enable RDS free diskspace monitor" + type = string + default = "true" +} + +variable "diskspace_extra_tags" { + description = "Extra tags for RDS free diskspace monitor" + type = list(string) + default = [] +} + +variable "diskspace_message" { + description = "Custom message for RDS free diskspace monitor" + type = string + default = "" +} + +variable "diskspace_time_aggregator" { + description = "Monitor aggregator for RDS free diskspace [available values: min, max or avg]" + type = string + default = "min" +} + +variable "diskspace_timeframe" { + description = "Monitor timeframe for RDS free diskspace [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "diskspace_threshold_warning" { + description = "Disk free space in percent (warning threshold)" + default = "20" +} + +variable "diskspace_threshold_critical" { + description = "Disk free space in percent (critical threshold)" + default = "10" +} + +variable "replicalag_enabled" { + description = "Flag to enable RDS replica lag monitor" + type = string + default = "true" +} + +variable "replicalag_extra_tags" { + description = "Extra tags for RDS replica lag monitor" + type = list(string) + default = [] +} + +variable "replicalag_message" { + description = "Custom message for RDS replica lag monitor" + type = string + default = "" +} + +variable "replicalag_time_aggregator" { + description = "Monitor aggregator for RDS replica lag [available values: min, max or avg]" + type = string + default = "min" +} + +variable "replicalag_timeframe" { + description = "Monitor timeframe for RDS replica lag monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "replicalag_threshold_warning" { + description = "replica lag in seconds (warning threshold)" + default = "200" +} + +variable "replicalag_threshold_critical" { + description = "replica lag in seconds (critical threshold)" + default = "300" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/common/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/common/modules.tf new file mode 100755 index 0000000..62fbd46 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/common/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../../common/filter-tags" + + environment = var.environment + resource = "aws_rds" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/common/monitors-rds-common.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/common/monitors-rds-common.tf new file mode 100755 index 0000000..cfbc30b --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/common/monitors-rds-common.tf @@ -0,0 +1,91 @@ +### RDS instance CPU monitor ### +resource "datadog_monitor" "rds_cpu_90_15min" { + count = var.cpu_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] RDS instance CPU high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cpu_message, var.message) + type = "query alert" + + query = < ${var.cpu_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.cpu_threshold_warning + critical = var.cpu_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:rds", "team:claranet", "created-by:terraform"], var.cpu_extra_tags) +} + +### RDS instance free space monitor ### +resource "datadog_monitor" "rds_free_space_low" { + count = var.diskspace_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] RDS instance free space {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.diskspace_message, var.message) + type = "query alert" + + query = < ${var.replicalag_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.replicalag_threshold_warning + critical = var.replicalag_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:rds", "team:claranet", "created-by:terraform"], var.replicalag_extra_tags) +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/common/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/common/outputs.tf new file mode 100755 index 0000000..e70b9b6 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/common/outputs.tf @@ -0,0 +1,15 @@ +output "rds_cpu_90_15min_id" { + description = "id for monitor rds_cpu_90_15min" + value = datadog_monitor.rds_cpu_90_15min.*.id +} + +output "rds_free_space_low_id" { + description = "id for monitor rds_free_space_low" + value = datadog_monitor.rds_free_space_low.*.id +} + +output "rds_replica_lag_id" { + description = "id for monitor rds_replica_lag" + value = datadog_monitor.rds_replica_lag.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/common/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/common/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/rds/common/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/sqs/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/sqs/README.md new file mode 100755 index 0000000..050663c --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/sqs/README.md @@ -0,0 +1,85 @@ +# CLOUD AWS SQS DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-sqs" { + source = "claranet/monitors/datadog//cloud/aws/sqs" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- SQS Age of the oldest message +- SQS Visible messages (disabled by default) + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.age_of_oldest_message](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.visible_messages](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [age\_of\_oldest\_message\_enabled](#input\_age\_of\_oldest\_message\_enabled) | Flag to enable Age of Oldest Message monitor | `string` | `"true"` | no | +| [age\_of\_oldest\_message\_extra\_tags](#input\_age\_of\_oldest\_message\_extra\_tags) | Extra tags for Age of Oldest Message monitor | `list(string)` | `[]` | no | +| [age\_of\_oldest\_message\_message](#input\_age\_of\_oldest\_message\_message) | Custom message for Age of Oldest Message monitor | `string` | `""` | no | +| [age\_of\_oldest\_message\_threshold\_critical](#input\_age\_of\_oldest\_message\_threshold\_critical) | Alerting threshold in seconds | `number` | `600` | no | +| [age\_of\_oldest\_message\_threshold\_warning](#input\_age\_of\_oldest\_message\_threshold\_warning) | Warning threshold in seconds | `number` | `300` | no | +| [age\_of\_oldest\_message\_time\_aggregator](#input\_age\_of\_oldest\_message\_time\_aggregator) | Monitor aggregator for Age of Oldest Message [available values: min, max or avg] | `string` | `"min"` | no | +| [age\_of\_oldest\_message\_timeframe](#input\_age\_of\_oldest\_message\_timeframe) | Monitor timeframe for Age of Oldest Message [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_30m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [visible\_messages\_enabled](#input\_visible\_messages\_enabled) | Flag to enable Number of Visible Messages monitor | `string` | `"false"` | no | +| [visible\_messages\_extra\_tags](#input\_visible\_messages\_extra\_tags) | Extra tags for Number of Visible Messages monitor | `list(string)` | `[]` | no | +| [visible\_messages\_message](#input\_visible\_messages\_message) | Custom message for Number of Visible Messages monitor | `string` | `""` | no | +| [visible\_messages\_threshold\_critical](#input\_visible\_messages\_threshold\_critical) | Alerting threshold in number of messages | `number` | `2` | no | +| [visible\_messages\_threshold\_warning](#input\_visible\_messages\_threshold\_warning) | Warning threshold in number of messages | `number` | `1` | no | +| [visible\_messages\_time\_aggregator](#input\_visible\_messages\_time\_aggregator) | Monitor aggregator for Number of Visible Messages [available values: min, max or avg] | `string` | `"min"` | no | +| [visible\_messages\_timeframe](#input\_visible\_messages\_timeframe) | Monitor timeframe for Number of Visible Messages [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_30m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [age\_of\_oldest\_message\_id](#output\_age\_of\_oldest\_message\_id) | id for monitor age\_of\_oldest\_message | +| [visible\_messages\_id](#output\_visible\_messages\_id) | id for monitor visible\_messages | +## Related documentation +* [Datadog Documentation](https://docs.datadoghq.com/integrations/amazon_sqs/) +* [Service Documentation](https://docs.aws.amazon.com/sqs/index.html) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/sqs/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/sqs/inputs.tf new file mode 100755 index 0000000..2f6acf6 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/sqs/inputs.tf @@ -0,0 +1,129 @@ +# Datadog global variables + +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# Datadog monitors variables + +# Approximate Number of Visible Messages +variable "visible_messages_enabled" { + description = "Flag to enable Number of Visible Messages monitor" + type = string + default = "false" +} + +variable "visible_messages_extra_tags" { + description = "Extra tags for Number of Visible Messages monitor" + type = list(string) + default = [] +} + +variable "visible_messages_message" { + description = "Custom message for Number of Visible Messages monitor" + type = string + default = "" +} + +variable "visible_messages_time_aggregator" { + description = "Monitor aggregator for Number of Visible Messages [available values: min, max or avg]" + type = string + default = "min" +} + +variable "visible_messages_timeframe" { + description = "Monitor timeframe for Number of Visible Messages [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_30m" +} + +variable "visible_messages_threshold_critical" { + default = 2 + description = "Alerting threshold in number of messages" +} + +variable "visible_messages_threshold_warning" { + default = 1 + description = "Warning threshold in number of messages" +} + +# Age of the Oldest Message +variable "age_of_oldest_message_enabled" { + description = "Flag to enable Age of Oldest Message monitor" + type = string + default = "true" +} + +variable "age_of_oldest_message_extra_tags" { + description = "Extra tags for Age of Oldest Message monitor" + type = list(string) + default = [] +} + +variable "age_of_oldest_message_message" { + description = "Custom message for Age of Oldest Message monitor" + type = string + default = "" +} + +variable "age_of_oldest_message_time_aggregator" { + description = "Monitor aggregator for Age of Oldest Message [available values: min, max or avg]" + type = string + default = "min" +} + +variable "age_of_oldest_message_timeframe" { + description = "Monitor timeframe for Age of Oldest Message [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_30m" +} + +variable "age_of_oldest_message_threshold_critical" { + default = 600 + description = "Alerting threshold in seconds" +} + +variable "age_of_oldest_message_threshold_warning" { + default = 300 + description = "Warning threshold in seconds" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/sqs/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/sqs/modules.tf new file mode 100755 index 0000000..291a7a5 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/sqs/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "aws_sqs" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/sqs/monitors-sqs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/sqs/monitors-sqs.tf new file mode 100755 index 0000000..794f69b --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/sqs/monitors-sqs.tf @@ -0,0 +1,61 @@ +# Approximate Number of Visible Messages +resource "datadog_monitor" "visible_messages" { + count = var.visible_messages_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] SQS Visible messages {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + type = "metric alert" + message = coalesce(var.visible_messages_message, var.message) + + query = < ${var.visible_messages_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.visible_messages_threshold_critical + warning = var.visible_messages_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:sqs", "team:claranet", "created-by:terraform"], var.visible_messages_extra_tags) +} + +# Age of the Oldest Message +resource "datadog_monitor" "age_of_oldest_message" { + count = var.age_of_oldest_message_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] SQS Age of the oldest message {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + type = "metric alert" + message = coalesce(var.age_of_oldest_message_message, var.message) + + query = < ${var.age_of_oldest_message_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.age_of_oldest_message_threshold_critical + warning = var.age_of_oldest_message_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:sqs", "team:claranet", "created-by:terraform"], var.age_of_oldest_message_extra_tags) +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/sqs/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/sqs/outputs.tf new file mode 100755 index 0000000..566853e --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/sqs/outputs.tf @@ -0,0 +1,10 @@ +output "age_of_oldest_message_id" { + description = "id for monitor age_of_oldest_message" + value = datadog_monitor.age_of_oldest_message.*.id +} + +output "visible_messages_id" { + description = "id for monitor visible_messages" + value = datadog_monitor.visible_messages.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/sqs/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/sqs/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/sqs/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/vpn/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/vpn/README.md new file mode 100755 index 0000000..09257ac --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/vpn/README.md @@ -0,0 +1,72 @@ +# CLOUD AWS VPN DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-vpn" { + source = "claranet/monitors/datadog//cloud/aws/vpn" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- VPN tunnel down + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.VPN_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags](#input\_filter\_tags) | Tags used for metrics filtering | `string` | `"*"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [vpn\_status\_enabled](#input\_vpn\_status\_enabled) | Flag to enable VPN status monitor | `string` | `"true"` | no | +| [vpn\_status\_extra\_tags](#input\_vpn\_status\_extra\_tags) | Extra tags for VPN status monitor | `list(string)` | `[]` | no | +| [vpn\_status\_message](#input\_vpn\_status\_message) | Custom message for VPN status monitor | `string` | `""` | no | +| [vpn\_status\_no\_data\_timeframe](#input\_vpn\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [vpn\_status\_time\_aggregator](#input\_vpn\_status\_time\_aggregator) | Monitor aggregator for VPN status [available values: min, max or avg] | `string` | `"max"` | no | +| [vpn\_status\_timeframe](#input\_vpn\_status\_timeframe) | Monitor timeframe for VPN status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [VPN\_status\_id](#output\_VPN\_status\_id) | id for monitor VPN\_status | +## Related documentation + +DataDog documentation: [https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/vpn-metricscollected.html](https://docs.datadoghq.com/integrations/amazon_web_services/) + +AWS VPN metrics documentation: [https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/vpn-metricscollected.html](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/vpn-metricscollected.html) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/vpn/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/vpn/inputs.tf new file mode 100755 index 0000000..1d6333a --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/vpn/inputs.tf @@ -0,0 +1,72 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "vpn_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags" { + description = "Tags used for metrics filtering" + default = "*" +} + +variable "vpn_status_enabled" { + description = "Flag to enable VPN status monitor" + type = string + default = "true" +} + +variable "vpn_status_extra_tags" { + description = "Extra tags for VPN status monitor" + type = list(string) + default = [] +} + +variable "vpn_status_message" { + description = "Custom message for VPN status monitor" + type = string + default = "" +} + +variable "vpn_status_time_aggregator" { + description = "Monitor aggregator for VPN status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "vpn_status_timeframe" { + description = "Monitor timeframe for VPN status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/vpn/monitors-vpn.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/vpn/monitors-vpn.tf new file mode 100755 index 0000000..728e846 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/aws/vpn/monitors-vpn.tf @@ -0,0 +1,25 @@ +resource "datadog_monitor" "VPN_status" { + count = var.vpn_status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] VPN tunnel down" + message = coalesce(var.vpn_status_message, var.message) + type = "query alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.apimgt_failed_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.apimgt_other_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.apimgt_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.apimgt_successful_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.apimgt_unauthorized_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [apimgt\_status\_no\_data\_timeframe](#input\_apimgt\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [failed\_requests\_enabled](#input\_failed\_requests\_enabled) | Flag to enable API Management failed requests monitor | `string` | `"true"` | no | +| [failed\_requests\_extra\_tags](#input\_failed\_requests\_extra\_tags) | Extra tags for API Management failed requests monitor | `list(string)` | `[]` | no | +| [failed\_requests\_message](#input\_failed\_requests\_message) | Custom message for API Management failed requests monitor | `string` | `""` | no | +| [failed\_requests\_threshold\_critical](#input\_failed\_requests\_threshold\_critical) | Maximum acceptable percent of failed requests | `number` | `90` | no | +| [failed\_requests\_threshold\_warning](#input\_failed\_requests\_threshold\_warning) | Warning regarding acceptable percent of failed requests | `number` | `50` | no | +| [failed\_requests\_time\_aggregator](#input\_failed\_requests\_time\_aggregator) | Monitor aggregator for API Management failed requests [available values: min, max or avg] | `string` | `"min"` | no | +| [failed\_requests\_timeframe](#input\_failed\_requests\_timeframe) | Monitor timeframe for API Management failed requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a Redis monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [other\_requests\_enabled](#input\_other\_requests\_enabled) | Flag to enable API Management other requests monitor | `string` | `"true"` | no | +| [other\_requests\_extra\_tags](#input\_other\_requests\_extra\_tags) | Extra tags for API Management other requests monitor | `list(string)` | `[]` | no | +| [other\_requests\_message](#input\_other\_requests\_message) | Custom message for API Management other requests monitor | `string` | `""` | no | +| [other\_requests\_threshold\_critical](#input\_other\_requests\_threshold\_critical) | Maximum acceptable percent of other requests | `number` | `90` | no | +| [other\_requests\_threshold\_warning](#input\_other\_requests\_threshold\_warning) | Warning regarding acceptable percent of other requests | `number` | `50` | no | +| [other\_requests\_time\_aggregator](#input\_other\_requests\_time\_aggregator) | Monitor aggregator for API Management other requests [available values: min, max or avg] | `string` | `"min"` | no | +| [other\_requests\_timeframe](#input\_other\_requests\_timeframe) | Monitor timeframe for API Management other requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable API Management status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for API Management status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for API Management status monitor | `string` | `""` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for API Management status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for API Management status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [successful\_requests\_enabled](#input\_successful\_requests\_enabled) | Flag to enable API Management successful requests monitor | `string` | `"true"` | no | +| [successful\_requests\_extra\_tags](#input\_successful\_requests\_extra\_tags) | Extra tags for API Management successful requests monitor | `list(string)` | `[]` | no | +| [successful\_requests\_message](#input\_successful\_requests\_message) | Custom message for API Management successful requests monitor | `string` | `""` | no | +| [successful\_requests\_threshold\_critical](#input\_successful\_requests\_threshold\_critical) | Minimum acceptable percent of successful requests | `number` | `10` | no | +| [successful\_requests\_threshold\_warning](#input\_successful\_requests\_threshold\_warning) | Warning regarding acceptable percent of successful requests | `number` | `30` | no | +| [successful\_requests\_time\_aggregator](#input\_successful\_requests\_time\_aggregator) | Monitor aggregator for API Management successful requests [available values: min, max or avg] | `string` | `"max"` | no | +| [successful\_requests\_timeframe](#input\_successful\_requests\_timeframe) | Monitor timeframe for API Management successful requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [unauthorized\_requests\_enabled](#input\_unauthorized\_requests\_enabled) | Flag to enable API Management unauthorized requests monitor | `string` | `"true"` | no | +| [unauthorized\_requests\_extra\_tags](#input\_unauthorized\_requests\_extra\_tags) | Extra tags for API Management unauthorized requests monitor | `list(string)` | `[]` | no | +| [unauthorized\_requests\_message](#input\_unauthorized\_requests\_message) | Custom message for API Management unauthorized requests monitor | `string` | `""` | no | +| [unauthorized\_requests\_threshold\_critical](#input\_unauthorized\_requests\_threshold\_critical) | Maximum acceptable percent of unauthorized requests | `number` | `90` | no | +| [unauthorized\_requests\_threshold\_warning](#input\_unauthorized\_requests\_threshold\_warning) | Warning regarding acceptable percent of unauthorized requests | `number` | `50` | no | +| [unauthorized\_requests\_time\_aggregator](#input\_unauthorized\_requests\_time\_aggregator) | Monitor aggregator for API Management unauthorized requests [available values: min, max or avg] | `string` | `"min"` | no | +| [unauthorized\_requests\_timeframe](#input\_unauthorized\_requests\_timeframe) | Monitor timeframe for API Management unauthorized requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [apimgt\_failed\_requests\_id](#output\_apimgt\_failed\_requests\_id) | id for monitor apimgt\_failed\_requests | +| [apimgt\_other\_requests\_id](#output\_apimgt\_other\_requests\_id) | id for monitor apimgt\_other\_requests | +| [apimgt\_status\_id](#output\_apimgt\_status\_id) | id for monitor apimgt\_status | +| [apimgt\_successful\_requests\_id](#output\_apimgt\_successful\_requests\_id) | id for monitor apimgt\_successful\_requests | +| [apimgt\_unauthorized\_requests\_id](#output\_apimgt\_unauthorized\_requests\_id) | id for monitor apimgt\_unauthorized\_requests | +## Related documentation + +Azure API Management metrics documentation: [https://docs.microsoft.com/en-us/azure/api-management/api-management-howto-use-azure-monitor](https://docs.microsoft.com/en-us/azure/api-management/api-management-howto-use-azure-monitor) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/apimanagement/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/apimanagement/inputs.tf new file mode 100755 index 0000000..da1fe59 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/apimanagement/inputs.tf @@ -0,0 +1,244 @@ +# Global Terraform +variable "environment" { + description = "Architecture environment" + type = string +} + +# Global DataDog +variable "message" { + description = "Message sent when a Redis monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "apimgt_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Azure API Management specific + +variable "status_enabled" { + description = "Flag to enable API Management status monitor" + type = string + default = "true" +} + +variable "status_extra_tags" { + description = "Extra tags for API Management status monitor" + type = list(string) + default = [] +} + +variable "status_message" { + description = "Custom message for API Management status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for API Management status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for API Management status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_requests_enabled" { + description = "Flag to enable API Management failed requests monitor" + type = string + default = "true" +} + +variable "failed_requests_extra_tags" { + description = "Extra tags for API Management failed requests monitor" + type = list(string) + default = [] +} + +variable "failed_requests_message" { + description = "Custom message for API Management failed requests monitor" + type = string + default = "" +} + +variable "failed_requests_time_aggregator" { + description = "Monitor aggregator for API Management failed requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "failed_requests_timeframe" { + description = "Monitor timeframe for API Management failed requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_requests_threshold_critical" { + description = "Maximum acceptable percent of failed requests" + default = 90 +} + +variable "failed_requests_threshold_warning" { + description = "Warning regarding acceptable percent of failed requests" + default = 50 +} + +variable "other_requests_enabled" { + description = "Flag to enable API Management other requests monitor" + type = string + default = "true" +} + +variable "other_requests_extra_tags" { + description = "Extra tags for API Management other requests monitor" + type = list(string) + default = [] +} + +variable "other_requests_message" { + description = "Custom message for API Management other requests monitor" + type = string + default = "" +} + +variable "other_requests_time_aggregator" { + description = "Monitor aggregator for API Management other requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "other_requests_timeframe" { + description = "Monitor timeframe for API Management other requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "other_requests_threshold_critical" { + description = "Maximum acceptable percent of other requests" + default = 90 +} + +variable "other_requests_threshold_warning" { + description = "Warning regarding acceptable percent of other requests" + default = 50 +} + +variable "unauthorized_requests_enabled" { + description = "Flag to enable API Management unauthorized requests monitor" + type = string + default = "true" +} + +variable "unauthorized_requests_extra_tags" { + description = "Extra tags for API Management unauthorized requests monitor" + type = list(string) + default = [] +} + +variable "unauthorized_requests_message" { + description = "Custom message for API Management unauthorized requests monitor" + type = string + default = "" +} + +variable "unauthorized_requests_time_aggregator" { + description = "Monitor aggregator for API Management unauthorized requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "unauthorized_requests_timeframe" { + description = "Monitor timeframe for API Management unauthorized requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "unauthorized_requests_threshold_critical" { + description = "Maximum acceptable percent of unauthorized requests" + default = 90 +} + +variable "unauthorized_requests_threshold_warning" { + description = "Warning regarding acceptable percent of unauthorized requests" + default = 50 +} + +variable "successful_requests_enabled" { + description = "Flag to enable API Management successful requests monitor" + type = string + default = "true" +} + +variable "successful_requests_extra_tags" { + description = "Extra tags for API Management successful requests monitor" + type = list(string) + default = [] +} + +variable "successful_requests_message" { + description = "Custom message for API Management successful requests monitor" + type = string + default = "" +} + +variable "successful_requests_time_aggregator" { + description = "Monitor aggregator for API Management successful requests [available values: min, max or avg]" + type = string + default = "max" +} + +variable "successful_requests_timeframe" { + description = "Monitor timeframe for API Management successful requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "successful_requests_threshold_critical" { + description = "Minimum acceptable percent of successful requests" + default = 10 +} + +variable "successful_requests_threshold_warning" { + description = "Warning regarding acceptable percent of successful requests" + default = 30 +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/apimanagement/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/apimanagement/modules.tf new file mode 100755 index 0000000..758b72e --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/apimanagement/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_apimanagement" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/apimanagement/monitors-azure-apimanagement.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/apimanagement/monitors-azure-apimanagement.tf new file mode 100755 index 0000000..fe4e060 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/apimanagement/monitors-azure-apimanagement.tf @@ -0,0 +1,154 @@ +resource "datadog_monitor" "apimgt_status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] API Management is down" + message = coalesce(var.status_message, var.message) + type = "metric alert" + + query = < ${var.failed_requests_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.failed_requests_threshold_critical + warning = var.failed_requests_threshold_warning + } + + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + notify_no_data = false + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:apimanagement", "team:claranet", "created-by:terraform"], var.failed_requests_extra_tags) +} + +resource "datadog_monitor" "apimgt_other_requests" { + count = var.other_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] API Management too many other requests {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.other_requests_message, var.message) + type = "query alert" + + query = < ${var.other_requests_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.other_requests_threshold_critical + warning = var.other_requests_threshold_warning + } + + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + notify_no_data = false + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:apimanagement", "team:claranet", "created-by:terraform"], var.other_requests_extra_tags) +} + +resource "datadog_monitor" "apimgt_unauthorized_requests" { + count = var.unauthorized_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] API Management too many unauthorized requests {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.unauthorized_requests_message, var.message) + type = "query alert" + + query = < ${var.unauthorized_requests_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.unauthorized_requests_threshold_critical + warning = var.unauthorized_requests_threshold_warning + } + + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + notify_no_data = false + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:apimanagement", "team:claranet", "created-by:terraform"], var.unauthorized_requests_extra_tags) +} + +resource "datadog_monitor" "apimgt_successful_requests" { + count = var.successful_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] API Management successful requests rate too low {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.successful_requests_message, var.message) + type = "query alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | +| [filter-tags-4xx-error](#module\_filter-tags-4xx-error) | ../../../common/filter-tags | n/a | +| [filter-tags-5xx-error](#module\_filter-tags-5xx-error) | ../../../common/filter-tags | n/a | +| [filter-tags-backend-4xx-error](#module\_filter-tags-backend-4xx-error) | ../../../common/filter-tags | n/a | +| [filter-tags-backend-5xx-error](#module\_filter-tags-backend-5xx-error) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.appgateway_backend_connect_time](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appgateway_backend_http_4xx_errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appgateway_backend_http_5xx_errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appgateway_failed_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appgateway_healthy_host_ratio](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appgateway_http_4xx_errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appgateway_http_5xx_errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appgateway_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.total_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [appgateway\_backend\_connect\_time\_enabled](#input\_appgateway\_backend\_connect\_time\_enabled) | Flag to enable App Gateway backend\_connect\_time monitor | `string` | `"true"` | no | +| [appgateway\_backend\_connect\_time\_extra\_tags](#input\_appgateway\_backend\_connect\_time\_extra\_tags) | Extra tags for App Gateway backend\_connect\_time monitor | `list(string)` | `[]` | no | +| [appgateway\_backend\_connect\_time\_message](#input\_appgateway\_backend\_connect\_time\_message) | Custom message for App Gateway backend\_connect\_time monitor | `string` | `""` | no | +| [appgateway\_backend\_connect\_time\_threshold\_critical](#input\_appgateway\_backend\_connect\_time\_threshold\_critical) | Maximum critical backend\_connect\_time errors in milliseconds | `number` | `50` | no | +| [appgateway\_backend\_connect\_time\_threshold\_warning](#input\_appgateway\_backend\_connect\_time\_threshold\_warning) | Warning regarding backend\_connect\_time errors in milliseconds | `number` | `40` | no | +| [appgateway\_backend\_connect\_time\_time\_aggregator](#input\_appgateway\_backend\_connect\_time\_time\_aggregator) | Monitor aggregator for App Gateway backend\_connect\_time [available values: min, max or avg] | `string` | `"max"` | no | +| [appgateway\_backend\_connect\_time\_timeframe](#input\_appgateway\_backend\_connect\_time\_timeframe) | Monitor timeframe for App Gateway backend\_connect\_time [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [appgateway\_backend\_http\_4xx\_errors\_enabled](#input\_appgateway\_backend\_http\_4xx\_errors\_enabled) | Flag to enable App Gateway http 4xx errors monitor | `string` | `"true"` | no | +| [appgateway\_backend\_http\_4xx\_errors\_extra\_tags](#input\_appgateway\_backend\_http\_4xx\_errors\_extra\_tags) | Extra tags for App Gateway http 4xx errors monitor | `list(string)` | `[]` | no | +| [appgateway\_backend\_http\_4xx\_errors\_message](#input\_appgateway\_backend\_http\_4xx\_errors\_message) | Custom message for App Gateway http 4xx errors monitor | `string` | `""` | no | +| [appgateway\_backend\_http\_4xx\_errors\_threshold\_critical](#input\_appgateway\_backend\_http\_4xx\_errors\_threshold\_critical) | Minimum critical acceptable percent of 4xx error | `number` | `95` | no | +| [appgateway\_backend\_http\_4xx\_errors\_threshold\_warning](#input\_appgateway\_backend\_http\_4xx\_errors\_threshold\_warning) | Warning regarding acceptable percent of 4xx error | `number` | `80` | no | +| [appgateway\_backend\_http\_4xx\_errors\_time\_aggregator](#input\_appgateway\_backend\_http\_4xx\_errors\_time\_aggregator) | Monitor aggregator for App Gateway http 4xx errors [available values: min, max or avg] | `string` | `"max"` | no | +| [appgateway\_backend\_http\_4xx\_errors\_timeframe](#input\_appgateway\_backend\_http\_4xx\_errors\_timeframe) | Monitor timeframe for App Gateway http 4xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [appgateway\_backend\_http\_5xx\_errors\_enabled](#input\_appgateway\_backend\_http\_5xx\_errors\_enabled) | Flag to enable App Gateway http 5xx errors monitor | `string` | `"true"` | no | +| [appgateway\_backend\_http\_5xx\_errors\_extra\_tags](#input\_appgateway\_backend\_http\_5xx\_errors\_extra\_tags) | Extra tags for App Gateway http 5xx errors monitor | `list(string)` | `[]` | no | +| [appgateway\_backend\_http\_5xx\_errors\_message](#input\_appgateway\_backend\_http\_5xx\_errors\_message) | Custom message for App Gateway http 5xx errors monitor | `string` | `""` | no | +| [appgateway\_backend\_http\_5xx\_errors\_threshold\_critical](#input\_appgateway\_backend\_http\_5xx\_errors\_threshold\_critical) | Minimum critical acceptable percent of 5xx error | `number` | `95` | no | +| [appgateway\_backend\_http\_5xx\_errors\_threshold\_warning](#input\_appgateway\_backend\_http\_5xx\_errors\_threshold\_warning) | Warning regarding acceptable percent of 5xx error | `number` | `80` | no | +| [appgateway\_backend\_http\_5xx\_errors\_time\_aggregator](#input\_appgateway\_backend\_http\_5xx\_errors\_time\_aggregator) | Monitor aggregator for App Gateway http 5xx errors [available values: min, max or avg] | `string` | `"max"` | no | +| [appgateway\_backend\_http\_5xx\_errors\_timeframe](#input\_appgateway\_backend\_http\_5xx\_errors\_timeframe) | Monitor timeframe for App Gateway http 5xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [appgateway\_failed\_requests\_enabled](#input\_appgateway\_failed\_requests\_enabled) | Flag to enable App Gateway failed requests monitor | `string` | `"true"` | no | +| [appgateway\_failed\_requests\_extra\_tags](#input\_appgateway\_failed\_requests\_extra\_tags) | Extra tags for App Gateway failed requests monitor | `list(string)` | `[]` | no | +| [appgateway\_failed\_requests\_message](#input\_appgateway\_failed\_requests\_message) | Custom message for App Gateway failed requests monitor | `string` | `""` | no | +| [appgateway\_failed\_requests\_threshold\_critical](#input\_appgateway\_failed\_requests\_threshold\_critical) | Maximum critical acceptable percent of failed errors | `number` | `95` | no | +| [appgateway\_failed\_requests\_threshold\_warning](#input\_appgateway\_failed\_requests\_threshold\_warning) | Warning regarding acceptable percent of failed errors | `number` | `80` | no | +| [appgateway\_failed\_requests\_time\_aggregator](#input\_appgateway\_failed\_requests\_time\_aggregator) | Monitor aggregator for App Gateway failed requests [available values: min, max or avg] | `string` | `"min"` | no | +| [appgateway\_failed\_requests\_timeframe](#input\_appgateway\_failed\_requests\_timeframe) | Monitor timeframe for App Gateway failed requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [appgateway\_http\_4xx\_errors\_enabled](#input\_appgateway\_http\_4xx\_errors\_enabled) | Flag to enable App Gateway http 4xx errors monitor | `string` | `"true"` | no | +| [appgateway\_http\_4xx\_errors\_extra\_tags](#input\_appgateway\_http\_4xx\_errors\_extra\_tags) | Extra tags for App Gateway http 4xx errors monitor | `list(string)` | `[]` | no | +| [appgateway\_http\_4xx\_errors\_message](#input\_appgateway\_http\_4xx\_errors\_message) | Custom message for App Gateway http 4xx errors monitor | `string` | `""` | no | +| [appgateway\_http\_4xx\_errors\_threshold\_critical](#input\_appgateway\_http\_4xx\_errors\_threshold\_critical) | Maximum critical acceptable percent of 4xx error | `number` | `95` | no | +| [appgateway\_http\_4xx\_errors\_threshold\_warning](#input\_appgateway\_http\_4xx\_errors\_threshold\_warning) | Warning regarding acceptable percent of 4xx error | `number` | `80` | no | +| [appgateway\_http\_4xx\_errors\_time\_aggregator](#input\_appgateway\_http\_4xx\_errors\_time\_aggregator) | Monitor aggregator for App Gateway http 4xx errors [available values: min, max or avg] | `string` | `"max"` | no | +| [appgateway\_http\_4xx\_errors\_timeframe](#input\_appgateway\_http\_4xx\_errors\_timeframe) | Monitor timeframe for App Gateway http 4xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [appgateway\_http\_5xx\_errors\_enabled](#input\_appgateway\_http\_5xx\_errors\_enabled) | Flag to enable App Gateway http 5xx errors monitor | `string` | `"true"` | no | +| [appgateway\_http\_5xx\_errors\_extra\_tags](#input\_appgateway\_http\_5xx\_errors\_extra\_tags) | Extra tags for App Gateway http 5xx errors monitor | `list(string)` | `[]` | no | +| [appgateway\_http\_5xx\_errors\_message](#input\_appgateway\_http\_5xx\_errors\_message) | Custom message for App Gateway http 5xx errors monitor | `string` | `""` | no | +| [appgateway\_http\_5xx\_errors\_threshold\_critical](#input\_appgateway\_http\_5xx\_errors\_threshold\_critical) | Maximum critical acceptable percent of 5xx error | `number` | `95` | no | +| [appgateway\_http\_5xx\_errors\_threshold\_warning](#input\_appgateway\_http\_5xx\_errors\_threshold\_warning) | Warning regarding acceptable percent of 5xx error | `number` | `80` | no | +| [appgateway\_http\_5xx\_errors\_time\_aggregator](#input\_appgateway\_http\_5xx\_errors\_time\_aggregator) | Monitor aggregator for App Gateway http 5xx errors [available values: min, max or avg] | `string` | `"max"` | no | +| [appgateway\_http\_5xx\_errors\_timeframe](#input\_appgateway\_http\_5xx\_errors\_timeframe) | Monitor timeframe for App Gateway http 5xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [appgateway\_status\_no\_data\_timeframe](#input\_appgateway\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [appgateway\_unhealthy\_host\_ratio\_enabled](#input\_appgateway\_unhealthy\_host\_ratio\_enabled) | Flag to enable App Gateway unhealthy host ratio monitor | `string` | `"true"` | no | +| [appgateway\_unhealthy\_host\_ratio\_extra\_tags](#input\_appgateway\_unhealthy\_host\_ratio\_extra\_tags) | Extra tags for App Gateway unhealthy host ratio monitor | `list(string)` | `[]` | no | +| [appgateway\_unhealthy\_host\_ratio\_message](#input\_appgateway\_unhealthy\_host\_ratio\_message) | Custom message for App Gateway unhealthy host ratio monitor | `string` | `""` | no | +| [appgateway\_unhealthy\_host\_ratio\_threshold\_critical](#input\_appgateway\_unhealthy\_host\_ratio\_threshold\_critical) | Maximum critical acceptable ratio of unhealthy host | `number` | `75` | no | +| [appgateway\_unhealthy\_host\_ratio\_threshold\_warning](#input\_appgateway\_unhealthy\_host\_ratio\_threshold\_warning) | Warning regarding acceptable ratio of unhealthy host | `number` | `50` | no | +| [appgateway\_unhealthy\_host\_ratio\_time\_aggregator](#input\_appgateway\_unhealthy\_host\_ratio\_time\_aggregator) | Monitor aggregator for App Gateway unhealthy host ratio [available values: min, max or avg] | `string` | `"max"` | no | +| [appgateway\_unhealthy\_host\_ratio\_timeframe](#input\_appgateway\_unhealthy\_host\_ratio\_timeframe) | Monitor timeframe for App Gateway unhealthy host ratio [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable App Gateway status | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for App Gateway status | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for App Gateway status | `string` | `""` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for App Gateway status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for App Gateway status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [total\_requests\_enabled](#input\_total\_requests\_enabled) | Flag to enable App Gateway current connections monitor | `string` | `"true"` | no | +| [total\_requests\_extra\_tags](#input\_total\_requests\_extra\_tags) | Extra tags for App Gateway current connections monitor | `list(string)` | `[]` | no | +| [total\_requests\_message](#input\_total\_requests\_message) | Custom message for App Gateway current connections monitor | `string` | `""` | no | +| [total\_requests\_time\_aggregator](#input\_total\_requests\_time\_aggregator) | Monitor aggregator for App Gateway current connections [available values: min, max or avg] | `string` | `"max"` | no | +| [total\_requests\_timeframe](#input\_total\_requests\_timeframe) | Monitor timeframe for App Gateway current connections [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [appgateway\_backend\_connect\_time\_id](#output\_appgateway\_backend\_connect\_time\_id) | id for monitor appgateway\_backend\_connect\_time | +| [appgateway\_backend\_http\_4xx\_errors\_id](#output\_appgateway\_backend\_http\_4xx\_errors\_id) | id for monitor appgateway\_backend\_http\_4xx\_errors | +| [appgateway\_backend\_http\_5xx\_errors\_id](#output\_appgateway\_backend\_http\_5xx\_errors\_id) | id for monitor appgateway\_backend\_http\_5xx\_errors | +| [appgateway\_failed\_requests\_id](#output\_appgateway\_failed\_requests\_id) | id for monitor appgateway\_failed\_requests | +| [appgateway\_healthy\_host\_ratio\_id](#output\_appgateway\_healthy\_host\_ratio\_id) | id for monitor appgateway\_healthy\_host\_ratio | +| [appgateway\_http\_4xx\_errors\_id](#output\_appgateway\_http\_4xx\_errors\_id) | id for monitor appgateway\_http\_4xx\_errors | +| [appgateway\_http\_5xx\_errors\_id](#output\_appgateway\_http\_5xx\_errors\_id) | id for monitor appgateway\_http\_5xx\_errors | +| [appgateway\_status\_id](#output\_appgateway\_status\_id) | id for monitor appgateway\_status | +| [total\_requests\_id](#output\_total\_requests\_id) | id for monitor total\_requests | +## Related documentation + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-gateway/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-gateway/inputs.tf new file mode 100755 index 0000000..2d37818 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-gateway/inputs.tf @@ -0,0 +1,400 @@ +# Azure App Gateway global variables +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "appgateway_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# Azure App Gateway specific variables +# Monitoring App Gateway status +variable "status_enabled" { + description = "Flag to enable App Gateway status" + type = string + default = "true" +} + +variable "status_extra_tags" { + description = "Extra tags for App Gateway status" + type = list(string) + default = [] +} + +variable "status_message" { + description = "Custom message for App Gateway status" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for App Gateway status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for App Gateway status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +# Monitoring App Gateway total_requests +variable "total_requests_enabled" { + description = "Flag to enable App Gateway current connections monitor" + type = string + default = "true" +} + +variable "total_requests_extra_tags" { + description = "Extra tags for App Gateway current connections monitor" + type = list(string) + default = [] +} + +variable "total_requests_message" { + description = "Custom message for App Gateway current connections monitor" + type = string + default = "" +} + +variable "total_requests_time_aggregator" { + description = "Monitor aggregator for App Gateway current connections [available values: min, max or avg]" + type = string + default = "max" +} + +variable "total_requests_timeframe" { + description = "Monitor timeframe for App Gateway current connections [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +# Monitoring App Gateway failed_requests +variable "appgateway_backend_connect_time_enabled" { + description = "Flag to enable App Gateway backend_connect_time monitor" + type = string + default = "true" +} + +variable "appgateway_backend_connect_time_extra_tags" { + description = "Extra tags for App Gateway backend_connect_time monitor" + type = list(string) + default = [] +} + +variable "appgateway_backend_connect_time_message" { + description = "Custom message for App Gateway backend_connect_time monitor" + type = string + default = "" +} + +variable "appgateway_backend_connect_time_time_aggregator" { + description = "Monitor aggregator for App Gateway backend_connect_time [available values: min, max or avg]" + type = string + default = "max" +} + +variable "appgateway_backend_connect_time_timeframe" { + description = "Monitor timeframe for App Gateway backend_connect_time [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "appgateway_backend_connect_time_threshold_critical" { + default = 50 + description = "Maximum critical backend_connect_time errors in milliseconds" +} + +variable "appgateway_backend_connect_time_threshold_warning" { + default = 40 + description = "Warning regarding backend_connect_time errors in milliseconds" +} + +# Monitoring App Gateway failed_requests +variable "appgateway_failed_requests_enabled" { + description = "Flag to enable App Gateway failed requests monitor" + type = string + default = "true" +} + +variable "appgateway_failed_requests_extra_tags" { + description = "Extra tags for App Gateway failed requests monitor" + type = list(string) + default = [] +} + +variable "appgateway_failed_requests_message" { + description = "Custom message for App Gateway failed requests monitor" + type = string + default = "" +} + +variable "appgateway_failed_requests_time_aggregator" { + description = "Monitor aggregator for App Gateway failed requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "appgateway_failed_requests_timeframe" { + description = "Monitor timeframe for App Gateway failed requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "appgateway_failed_requests_threshold_critical" { + default = 95 + description = "Maximum critical acceptable percent of failed errors" +} + +variable "appgateway_failed_requests_threshold_warning" { + default = 80 + description = "Warning regarding acceptable percent of failed errors" +} + +# Monitoring App Gateway unhealthy_host_ratio +variable "appgateway_unhealthy_host_ratio_enabled" { + description = "Flag to enable App Gateway unhealthy host ratio monitor" + type = string + default = "true" +} + +variable "appgateway_unhealthy_host_ratio_extra_tags" { + description = "Extra tags for App Gateway unhealthy host ratio monitor" + type = list(string) + default = [] +} + +variable "appgateway_unhealthy_host_ratio_message" { + description = "Custom message for App Gateway unhealthy host ratio monitor" + type = string + default = "" +} + +variable "appgateway_unhealthy_host_ratio_time_aggregator" { + description = "Monitor aggregator for App Gateway unhealthy host ratio [available values: min, max or avg]" + type = string + default = "max" +} + +variable "appgateway_unhealthy_host_ratio_timeframe" { + description = "Monitor timeframe for App Gateway unhealthy host ratio [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "appgateway_unhealthy_host_ratio_threshold_critical" { + default = 75 + description = "Maximum critical acceptable ratio of unhealthy host" +} + +variable "appgateway_unhealthy_host_ratio_threshold_warning" { + default = 50 + description = "Warning regarding acceptable ratio of unhealthy host" +} + +# Monitoring App Gateway response_status 4xx +variable "appgateway_http_4xx_errors_enabled" { + description = "Flag to enable App Gateway http 4xx errors monitor" + type = string + default = "true" +} + +variable "appgateway_http_4xx_errors_extra_tags" { + description = "Extra tags for App Gateway http 4xx errors monitor" + type = list(string) + default = [] +} + +variable "appgateway_http_4xx_errors_message" { + description = "Custom message for App Gateway http 4xx errors monitor" + type = string + default = "" +} + +variable "appgateway_http_4xx_errors_time_aggregator" { + description = "Monitor aggregator for App Gateway http 4xx errors [available values: min, max or avg]" + type = string + default = "max" +} + +variable "appgateway_http_4xx_errors_timeframe" { + description = "Monitor timeframe for App Gateway http 4xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "appgateway_http_4xx_errors_threshold_critical" { + default = 95 + description = "Maximum critical acceptable percent of 4xx error" +} + +variable "appgateway_http_4xx_errors_threshold_warning" { + default = 80 + description = "Warning regarding acceptable percent of 4xx error" +} + +# Monitoring App Gateway response_status 5xx +variable "appgateway_http_5xx_errors_enabled" { + description = "Flag to enable App Gateway http 5xx errors monitor" + type = string + default = "true" +} + +variable "appgateway_http_5xx_errors_extra_tags" { + description = "Extra tags for App Gateway http 5xx errors monitor" + type = list(string) + default = [] +} + +variable "appgateway_http_5xx_errors_message" { + description = "Custom message for App Gateway http 5xx errors monitor" + type = string + default = "" +} + +variable "appgateway_http_5xx_errors_time_aggregator" { + description = "Monitor aggregator for App Gateway http 5xx errors [available values: min, max or avg]" + type = string + default = "max" +} + +variable "appgateway_http_5xx_errors_timeframe" { + description = "Monitor timeframe for App Gateway http 5xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "appgateway_http_5xx_errors_threshold_critical" { + default = 95 + description = "Maximum critical acceptable percent of 5xx error" +} + +variable "appgateway_http_5xx_errors_threshold_warning" { + default = 80 + description = "Warning regarding acceptable percent of 5xx error" +} + +# Monitoring App Gateway Backend response_status 4xx +variable "appgateway_backend_http_4xx_errors_enabled" { + description = "Flag to enable App Gateway http 4xx errors monitor" + type = string + default = "true" +} + +variable "appgateway_backend_http_4xx_errors_extra_tags" { + description = "Extra tags for App Gateway http 4xx errors monitor" + type = list(string) + default = [] +} + +variable "appgateway_backend_http_4xx_errors_message" { + description = "Custom message for App Gateway http 4xx errors monitor" + type = string + default = "" +} + +variable "appgateway_backend_http_4xx_errors_time_aggregator" { + description = "Monitor aggregator for App Gateway http 4xx errors [available values: min, max or avg]" + type = string + default = "max" +} + +variable "appgateway_backend_http_4xx_errors_timeframe" { + description = "Monitor timeframe for App Gateway http 4xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "appgateway_backend_http_4xx_errors_threshold_critical" { + default = 95 + description = "Minimum critical acceptable percent of 4xx error" +} + +variable "appgateway_backend_http_4xx_errors_threshold_warning" { + default = 80 + description = "Warning regarding acceptable percent of 4xx error" +} + +# Monitoring App Gateway Backend response_status 5xx +variable "appgateway_backend_http_5xx_errors_enabled" { + description = "Flag to enable App Gateway http 5xx errors monitor" + type = string + default = "true" +} + +variable "appgateway_backend_http_5xx_errors_extra_tags" { + description = "Extra tags for App Gateway http 5xx errors monitor" + type = list(string) + default = [] +} + +variable "appgateway_backend_http_5xx_errors_message" { + description = "Custom message for App Gateway http 5xx errors monitor" + type = string + default = "" +} + +variable "appgateway_backend_http_5xx_errors_time_aggregator" { + description = "Monitor aggregator for App Gateway http 5xx errors [available values: min, max or avg]" + type = string + default = "max" +} + +variable "appgateway_backend_http_5xx_errors_timeframe" { + description = "Monitor timeframe for App Gateway http 5xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "appgateway_backend_http_5xx_errors_threshold_critical" { + default = 95 + description = "Minimum critical acceptable percent of 5xx error" +} + +variable "appgateway_backend_http_5xx_errors_threshold_warning" { + default = 80 + description = "Warning regarding acceptable percent of 5xx error" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-gateway/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-gateway/modules.tf new file mode 100755 index 0000000..12b0c58 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-gateway/modules.tf @@ -0,0 +1,53 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_app-gateway" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + +module "filter-tags-4xx-error" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_app-gateway" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["httpstatusgroup:4xx"] +} + +module "filter-tags-5xx-error" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_app-gateway" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["httpstatusgroup:5xx"] +} + +module "filter-tags-backend-4xx-error" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_app-gateway" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["httpstatusgroup:4xx"] +} + +module "filter-tags-backend-5xx-error" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_app-gateway" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["httpstatusgroup:5xx"] +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-gateway/monitors-app-gateway.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-gateway/monitors-app-gateway.tf new file mode 100755 index 0000000..7680ac2 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-gateway/monitors-app-gateway.tf @@ -0,0 +1,267 @@ +# Monitoring App Gateway status +resource "datadog_monitor" "appgateway_status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Gateway is down" + message = coalesce(var.status_message, var.message) + type = "metric alert" + + query = < ${var.appgateway_backend_connect_time_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.appgateway_backend_connect_time_threshold_critical + warning = var.appgateway_backend_connect_time_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:app-gateway", "team:claranet", "created-by:terraform"], var.appgateway_backend_connect_time_extra_tags) +} + +# Monitoring App Gateway failed_requests +resource "datadog_monitor" "appgateway_failed_requests" { + count = var.appgateway_failed_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Gateway failed requests {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.appgateway_failed_requests_message, var.message) + type = "query alert" + + query = < ${var.appgateway_failed_requests_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.appgateway_failed_requests_threshold_critical + warning = var.appgateway_failed_requests_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:app-gateway", "team:claranet", "created-by:terraform"], var.appgateway_failed_requests_extra_tags) +} + +# Monitoring App Gateway unhealthy_host_ratio +resource "datadog_monitor" "appgateway_healthy_host_ratio" { + count = var.appgateway_unhealthy_host_ratio_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Gateway backend unhealthy host ratio is too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.appgateway_unhealthy_host_ratio_message, var.message) + type = "query alert" + + query = < ${var.appgateway_unhealthy_host_ratio_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.appgateway_unhealthy_host_ratio_threshold_critical + warning = var.appgateway_unhealthy_host_ratio_threshold_warning + } + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:app-gateway", "team:claranet", "created-by:terraform"], var.appgateway_unhealthy_host_ratio_extra_tags) +} + +# Monitoring App Gateway response_status 4xx +resource "datadog_monitor" "appgateway_http_4xx_errors" { + count = var.appgateway_http_4xx_errors_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Gateway HTTP 4xx errors rate is too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.appgateway_http_4xx_errors_message, var.message) + type = "query alert" + + query = < ${var.appgateway_http_4xx_errors_threshold_critical} +EOQ + + + monitor_thresholds { + warning = var.appgateway_http_4xx_errors_threshold_warning + critical = var.appgateway_http_4xx_errors_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 1 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:app-gateway", "team:claranet", "created-by:terraform"], var.appgateway_http_4xx_errors_extra_tags) +} + +# Monitoring App Gateway response_status 5xx +resource "datadog_monitor" "appgateway_http_5xx_errors" { + count = var.appgateway_http_5xx_errors_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Gateway HTTP 5xx errors rate is too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.appgateway_http_5xx_errors_message, var.message) + type = "query alert" + + query = < ${var.appgateway_http_5xx_errors_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.appgateway_http_5xx_errors_threshold_warning + critical = var.appgateway_http_5xx_errors_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 1 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:app-gateway", "team:claranet", "created-by:terraform"], var.appgateway_http_5xx_errors_extra_tags) +} + +# Monitoring App Gateway Backend response_status 4xx +resource "datadog_monitor" "appgateway_backend_http_4xx_errors" { + count = var.appgateway_backend_http_4xx_errors_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Gateway backend HTTP 4xx errors rate is too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.appgateway_backend_http_4xx_errors_message, var.message) + type = "query alert" + + query = < ${var.appgateway_backend_http_4xx_errors_threshold_critical} +EOQ + + + monitor_thresholds { + warning = var.appgateway_backend_http_4xx_errors_threshold_warning + critical = var.appgateway_backend_http_4xx_errors_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 1 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:app-gateway", "team:claranet", "created-by:terraform"], var.appgateway_backend_http_4xx_errors_extra_tags) +} + +# Monitoring App Gateway Backend response_status 5xx +resource "datadog_monitor" "appgateway_backend_http_5xx_errors" { + count = var.appgateway_backend_http_5xx_errors_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Gateway backend HTTP 5xx errors rate is too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.appgateway_backend_http_5xx_errors_message, var.message) + type = "query alert" + + query = < ${var.appgateway_backend_http_5xx_errors_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.appgateway_backend_http_5xx_errors_threshold_warning + critical = var.appgateway_backend_http_5xx_errors_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 1 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:app-gateway", "team:claranet", "created-by:terraform"], var.appgateway_backend_http_5xx_errors_extra_tags) +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-gateway/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-gateway/outputs.tf new file mode 100755 index 0000000..e291598 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-gateway/outputs.tf @@ -0,0 +1,45 @@ +output "appgateway_backend_connect_time_id" { + description = "id for monitor appgateway_backend_connect_time" + value = datadog_monitor.appgateway_backend_connect_time.*.id +} + +output "appgateway_backend_http_4xx_errors_id" { + description = "id for monitor appgateway_backend_http_4xx_errors" + value = datadog_monitor.appgateway_backend_http_4xx_errors.*.id +} + +output "appgateway_backend_http_5xx_errors_id" { + description = "id for monitor appgateway_backend_http_5xx_errors" + value = datadog_monitor.appgateway_backend_http_5xx_errors.*.id +} + +output "appgateway_failed_requests_id" { + description = "id for monitor appgateway_failed_requests" + value = datadog_monitor.appgateway_failed_requests.*.id +} + +output "appgateway_healthy_host_ratio_id" { + description = "id for monitor appgateway_healthy_host_ratio" + value = datadog_monitor.appgateway_healthy_host_ratio.*.id +} + +output "appgateway_http_4xx_errors_id" { + description = "id for monitor appgateway_http_4xx_errors" + value = datadog_monitor.appgateway_http_4xx_errors.*.id +} + +output "appgateway_http_5xx_errors_id" { + description = "id for monitor appgateway_http_5xx_errors" + value = datadog_monitor.appgateway_http_5xx_errors.*.id +} + +output "appgateway_status_id" { + description = "id for monitor appgateway_status" + value = datadog_monitor.appgateway_status.*.id +} + +output "total_requests_id" { + description = "id for monitor total_requests" + value = datadog_monitor.total_requests.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-gateway/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-gateway/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-gateway/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-services/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-services/README.md new file mode 100755 index 0000000..fbd62be --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-services/README.md @@ -0,0 +1,124 @@ +# CLOUD AZURE APP-SERVICES DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-app-services" { + source = "claranet/monitors/datadog//cloud/azure/app-services" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- App Services HTTP 4xx errors too high +- App Services HTTP 5xx errors too high +- App Services HTTP successful responses too low +- App Services is down +- App Services memory usage +- App Services response time too high + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.appservices_http_4xx_errors_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appservices_http_5xx_errors_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appservices_http_success_status_rate](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appservices_memory_usage_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appservices_response_time](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appservices_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [appservices\_status\_no\_data\_timeframe](#input\_appservices\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [http\_4xx\_requests\_enabled](#input\_http\_4xx\_requests\_enabled) | Flag to enable App Services 4xx requests monitor | `string` | `"true"` | no | +| [http\_4xx\_requests\_extra\_tags](#input\_http\_4xx\_requests\_extra\_tags) | Extra tags for App Services 4xx requests monitor | `list(string)` | `[]` | no | +| [http\_4xx\_requests\_message](#input\_http\_4xx\_requests\_message) | Custom message for App Services 4xx requests monitor | `string` | `""` | no | +| [http\_4xx\_requests\_threshold\_critical](#input\_http\_4xx\_requests\_threshold\_critical) | Maximum critical acceptable percent of 4xx errors | `number` | `90` | no | +| [http\_4xx\_requests\_threshold\_warning](#input\_http\_4xx\_requests\_threshold\_warning) | Warning regarding acceptable percent of 4xx errors | `number` | `50` | no | +| [http\_4xx\_requests\_time\_aggregator](#input\_http\_4xx\_requests\_time\_aggregator) | Monitor aggregator for App Services 4xx requests [available values: min, max or avg] | `string` | `"min"` | no | +| [http\_4xx\_requests\_timeframe](#input\_http\_4xx\_requests\_timeframe) | Monitor timeframe for App Services 4xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [http\_5xx\_requests\_enabled](#input\_http\_5xx\_requests\_enabled) | Flag to enable App Services 5xx requests monitor | `string` | `"true"` | no | +| [http\_5xx\_requests\_extra\_tags](#input\_http\_5xx\_requests\_extra\_tags) | Extra tags for App Services 5xx requests monitor | `list(string)` | `[]` | no | +| [http\_5xx\_requests\_message](#input\_http\_5xx\_requests\_message) | Custom message for App Services 5xx requests monitor | `string` | `""` | no | +| [http\_5xx\_requests\_threshold\_critical](#input\_http\_5xx\_requests\_threshold\_critical) | Maximum critical acceptable percent of 5xx errors | `number` | `90` | no | +| [http\_5xx\_requests\_threshold\_warning](#input\_http\_5xx\_requests\_threshold\_warning) | Warning regarding acceptable percent of 5xx errors | `number` | `50` | no | +| [http\_5xx\_requests\_time\_aggregator](#input\_http\_5xx\_requests\_time\_aggregator) | Monitor aggregator for App Services 5xx requests [available values: min, max or avg] | `string` | `"min"` | no | +| [http\_5xx\_requests\_timeframe](#input\_http\_5xx\_requests\_timeframe) | Monitor timeframe for App Services 5xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [http\_successful\_requests\_enabled](#input\_http\_successful\_requests\_enabled) | Flag to enable App Services successful requests monitor | `string` | `"true"` | no | +| [http\_successful\_requests\_extra\_tags](#input\_http\_successful\_requests\_extra\_tags) | Extra tags for App Services successful requests monitor | `list(string)` | `[]` | no | +| [http\_successful\_requests\_message](#input\_http\_successful\_requests\_message) | Custom message for App Services successful requests monitor | `string` | `""` | no | +| [http\_successful\_requests\_threshold\_critical](#input\_http\_successful\_requests\_threshold\_critical) | Minimum critical acceptable percent of 2xx & 3xx requests | `number` | `10` | no | +| [http\_successful\_requests\_threshold\_warning](#input\_http\_successful\_requests\_threshold\_warning) | Warning regarding acceptable percent of 2xx & 3xx requests | `number` | `30` | no | +| [http\_successful\_requests\_time\_aggregator](#input\_http\_successful\_requests\_time\_aggregator) | Monitor aggregator for App Services successful requests [available values: min, max or avg] | `string` | `"max"` | no | +| [http\_successful\_requests\_timeframe](#input\_http\_successful\_requests\_timeframe) | Monitor timeframe for App Services successful requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [memory\_usage\_enabled](#input\_memory\_usage\_enabled) | Flag to enable App Services memory usage monitor | `string` | `"true"` | no | +| [memory\_usage\_extra\_tags](#input\_memory\_usage\_extra\_tags) | Extra tags for App Services memory usage monitor | `list(string)` | `[]` | no | +| [memory\_usage\_message](#input\_memory\_usage\_message) | Custom message for App Services memory usage monitor | `string` | `""` | no | +| [memory\_usage\_threshold\_critical](#input\_memory\_usage\_threshold\_critical) | Alerting threshold in Mib | `number` | `1073741824` | no | +| [memory\_usage\_threshold\_warning](#input\_memory\_usage\_threshold\_warning) | Warning threshold in MiB | `number` | `536870912` | no | +| [memory\_usage\_time\_aggregator](#input\_memory\_usage\_time\_aggregator) | Monitor aggregator for App Services memory usage [available values: min, max or avg] | `string` | `"min"` | no | +| [memory\_usage\_timeframe](#input\_memory\_usage\_timeframe) | Monitor timeframe for App Services memory usage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [response\_time\_enabled](#input\_response\_time\_enabled) | Flag to enable App Services response time monitor | `string` | `"true"` | no | +| [response\_time\_extra\_tags](#input\_response\_time\_extra\_tags) | Extra tags for App Services response time monitor | `list(string)` | `[]` | no | +| [response\_time\_message](#input\_response\_time\_message) | Custom message for App Services response time monitor | `string` | `""` | no | +| [response\_time\_threshold\_critical](#input\_response\_time\_threshold\_critical) | Alerting threshold for response time in seconds | `number` | `10` | no | +| [response\_time\_threshold\_warning](#input\_response\_time\_threshold\_warning) | Warning threshold for response time in seconds | `number` | `5` | no | +| [response\_time\_time\_aggregator](#input\_response\_time\_time\_aggregator) | Monitor aggregator for App Services response time [available values: min, max or avg] | `string` | `"min"` | no | +| [response\_time\_timeframe](#input\_response\_time\_timeframe) | Monitor timeframe for App Services response time [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable App Services status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for App Services status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for App Services status monitor | `string` | `""` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for App Services status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for App Services status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [appservices\_http\_4xx\_errors\_count\_id](#output\_appservices\_http\_4xx\_errors\_count\_id) | id for monitor appservices\_http\_4xx\_errors\_count | +| [appservices\_http\_5xx\_errors\_count\_id](#output\_appservices\_http\_5xx\_errors\_count\_id) | id for monitor appservices\_http\_5xx\_errors\_count | +| [appservices\_http\_success\_status\_rate\_id](#output\_appservices\_http\_success\_status\_rate\_id) | id for monitor appservices\_http\_success\_status\_rate | +| [appservices\_memory\_usage\_count\_id](#output\_appservices\_memory\_usage\_count\_id) | id for monitor appservices\_memory\_usage\_count | +| [appservices\_response\_time\_id](#output\_appservices\_response\_time\_id) | id for monitor appservices\_response\_time | +| [appservices\_status\_id](#output\_appservices\_status\_id) | id for monitor appservices\_status | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure_app_services](https://docs.datadoghq.com/integrations/azure_app_services) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-services/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-services/inputs.tf new file mode 100755 index 0000000..a0c9b0e --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-services/inputs.tf @@ -0,0 +1,282 @@ +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "appservices_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# Azure App Services specific variables + +variable "response_time_enabled" { + description = "Flag to enable App Services response time monitor" + type = string + default = "true" +} + +variable "response_time_extra_tags" { + description = "Extra tags for App Services response time monitor" + type = list(string) + default = [] +} + +variable "response_time_message" { + description = "Custom message for App Services response time monitor" + type = string + default = "" +} + +variable "response_time_time_aggregator" { + description = "Monitor aggregator for App Services response time [available values: min, max or avg]" + type = string + default = "min" +} + +variable "response_time_timeframe" { + description = "Monitor timeframe for App Services response time [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "response_time_threshold_critical" { + default = 10 + description = "Alerting threshold for response time in seconds" +} + +variable "response_time_threshold_warning" { + default = 5 + description = "Warning threshold for response time in seconds" +} + +variable "memory_usage_enabled" { + description = "Flag to enable App Services memory usage monitor" + type = string + default = "true" +} + +variable "memory_usage_extra_tags" { + description = "Extra tags for App Services memory usage monitor" + type = list(string) + default = [] +} + +variable "memory_usage_message" { + description = "Custom message for App Services memory usage monitor" + type = string + default = "" +} + +variable "memory_usage_time_aggregator" { + description = "Monitor aggregator for App Services memory usage [available values: min, max or avg]" + type = string + default = "min" +} + +variable "memory_usage_timeframe" { + description = "Monitor timeframe for App Services memory usage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "memory_usage_threshold_critical" { + default = 1073741824 # 1Gb + description = "Alerting threshold in Mib" +} + +variable "memory_usage_threshold_warning" { + default = 536870912 # 512Mb + description = "Warning threshold in MiB" +} + +variable "http_4xx_requests_enabled" { + description = "Flag to enable App Services 4xx requests monitor" + type = string + default = "true" +} + +variable "http_4xx_requests_extra_tags" { + description = "Extra tags for App Services 4xx requests monitor" + type = list(string) + default = [] +} + +variable "http_4xx_requests_message" { + description = "Custom message for App Services 4xx requests monitor" + type = string + default = "" +} + +variable "http_4xx_requests_time_aggregator" { + description = "Monitor aggregator for App Services 4xx requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "http_4xx_requests_timeframe" { + description = "Monitor timeframe for App Services 4xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "http_4xx_requests_threshold_critical" { + default = 90 + description = "Maximum critical acceptable percent of 4xx errors" +} + +variable "http_4xx_requests_threshold_warning" { + default = 50 + description = "Warning regarding acceptable percent of 4xx errors" +} + +variable "http_5xx_requests_enabled" { + description = "Flag to enable App Services 5xx requests monitor" + type = string + default = "true" +} + +variable "http_5xx_requests_extra_tags" { + description = "Extra tags for App Services 5xx requests monitor" + type = list(string) + default = [] +} + +variable "http_5xx_requests_message" { + description = "Custom message for App Services 5xx requests monitor" + type = string + default = "" +} + +variable "http_5xx_requests_time_aggregator" { + description = "Monitor aggregator for App Services 5xx requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "http_5xx_requests_timeframe" { + description = "Monitor timeframe for App Services 5xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "http_5xx_requests_threshold_critical" { + default = 90 + description = "Maximum critical acceptable percent of 5xx errors" +} + +variable "http_5xx_requests_threshold_warning" { + default = 50 + description = "Warning regarding acceptable percent of 5xx errors" +} + +variable "http_successful_requests_enabled" { + description = "Flag to enable App Services successful requests monitor" + type = string + default = "true" +} + +variable "http_successful_requests_extra_tags" { + description = "Extra tags for App Services successful requests monitor" + type = list(string) + default = [] +} + +variable "http_successful_requests_message" { + description = "Custom message for App Services successful requests monitor" + type = string + default = "" +} + +variable "http_successful_requests_time_aggregator" { + description = "Monitor aggregator for App Services successful requests [available values: min, max or avg]" + type = string + default = "max" +} + +variable "http_successful_requests_timeframe" { + description = "Monitor timeframe for App Services successful requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "http_successful_requests_threshold_critical" { + default = 10 + description = "Minimum critical acceptable percent of 2xx & 3xx requests" +} + +variable "http_successful_requests_threshold_warning" { + default = 30 + description = "Warning regarding acceptable percent of 2xx & 3xx requests" +} + +variable "status_enabled" { + description = "Flag to enable App Services status monitor" + type = string + default = "true" +} + +variable "status_message" { + description = "Custom message for App Services status monitor" + type = string + default = "" +} + +variable "status_extra_tags" { + description = "Extra tags for App Services status monitor" + type = list(string) + default = [] +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for App Services status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for App Services status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-services/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-services/modules.tf new file mode 100755 index 0000000..6fe848d --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-services/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_app-services" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-services/monitors-app_services.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-services/monitors-app_services.tf new file mode 100755 index 0000000..319d203 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/app-services/monitors-app_services.tf @@ -0,0 +1,177 @@ +# Monitoring App Services response time +resource "datadog_monitor" "appservices_response_time" { + count = var.response_time_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Services response time too high {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + message = coalesce(var.response_time_message, var.message) + type = "query alert" + + query = < ${var.response_time_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.response_time_threshold_warning + critical = var.response_time_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:app-services", "team:claranet", "created-by:terraform"], var.response_time_extra_tags) +} + +# Monitoring App Services memory usage +resource "datadog_monitor" "appservices_memory_usage_count" { + count = var.memory_usage_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Services memory usage {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.memory_usage_message, var.message) + type = "query alert" + + query = < ${var.memory_usage_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.memory_usage_threshold_warning + critical = var.memory_usage_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:app-services", "team:claranet", "created-by:terraform"], var.memory_usage_extra_tags) +} + +# Monitoring App Services 5xx errors percent +resource "datadog_monitor" "appservices_http_5xx_errors_count" { + count = var.http_5xx_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Services HTTP 5xx errors too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.http_5xx_requests_message, var.message) + type = "query alert" + + query = < ${var.http_5xx_requests_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.http_5xx_requests_threshold_warning + critical = var.http_5xx_requests_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 1 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:app-services", "team:claranet", "created-by:terraform"], var.http_5xx_requests_extra_tags) +} + +# Monitoring App Services 4xx errors percent +resource "datadog_monitor" "appservices_http_4xx_errors_count" { + count = var.http_4xx_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Services HTTP 4xx errors too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.http_4xx_requests_message, var.message) + type = "query alert" + + query = < ${var.http_4xx_requests_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.http_4xx_requests_threshold_warning + critical = var.http_4xx_requests_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false # Will NOT notify when no data is received + renotify_interval = 0 + require_full_window = false + timeout_h = 1 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:app-services", "team:claranet", "created-by:terraform"], var.http_4xx_requests_extra_tags) +} + +# Monitoring App Services HTTP 2xx & 3xx status pages percent +resource "datadog_monitor" "appservices_http_success_status_rate" { + count = var.http_successful_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Services HTTP successful responses too low {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + type = "query alert" + message = coalesce(var.http_successful_requests_message, var.message) + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.azure_search_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.azure_search_throttled_queries_rate](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [azure\_search\_latency\_no\_data\_timeframe](#input\_azure\_search\_latency\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [latency\_enabled](#input\_latency\_enabled) | Flag to enable Azure Search latency monitor | `string` | `"true"` | no | +| [latency\_extra\_tags](#input\_latency\_extra\_tags) | Extra tags for Azure Search latency monitor | `list(string)` | `[]` | no | +| [latency\_message](#input\_latency\_message) | Custom message for Azure Search latency monitor | `string` | `""` | no | +| [latency\_threshold\_critical](#input\_latency\_threshold\_critical) | Alerting threshold for Azure Search latency in seconds | `number` | `4` | no | +| [latency\_threshold\_warning](#input\_latency\_threshold\_warning) | Warning threshold for Azure Search latency in seconds | `number` | `2` | no | +| [latency\_time\_aggregator](#input\_latency\_time\_aggregator) | Monitor aggregator for Azure Search latency [available values: min, max or avg] | `string` | `"min"` | no | +| [latency\_timeframe](#input\_latency\_timeframe) | Monitor timeframe for Azure Search latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [throttled\_queries\_rate\_enabled](#input\_throttled\_queries\_rate\_enabled) | Flag to enable Azure Search throttled queries rate monitor | `string` | `"true"` | no | +| [throttled\_queries\_rate\_extra\_tags](#input\_throttled\_queries\_rate\_extra\_tags) | Extra tags for Azure Search throttled queries rate monitor | `list(string)` | `[]` | no | +| [throttled\_queries\_rate\_message](#input\_throttled\_queries\_rate\_message) | Custom message for Azure Search throttled queries rate monitor | `string` | `""` | no | +| [throttled\_queries\_rate\_threshold\_critical](#input\_throttled\_queries\_rate\_threshold\_critical) | Alerting threshold for Azure Search throttled queries rate | `number` | `50` | no | +| [throttled\_queries\_rate\_threshold\_warning](#input\_throttled\_queries\_rate\_threshold\_warning) | Warning threshold for Azure Search throttled queries rate | `number` | `25` | no | +| [throttled\_queries\_rate\_time\_aggregator](#input\_throttled\_queries\_rate\_time\_aggregator) | Monitor aggregator for Azure Search throttled queries rate [available values: min, max or avg] | `string` | `"min"` | no | +| [throttled\_queries\_rate\_timeframe](#input\_throttled\_queries\_rate\_timeframe) | Monitor timeframe for Azure Search throttled queries rate [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [azure\_search\_latency\_id](#output\_azure\_search\_latency\_id) | id for monitor azure\_search\_latency | +| [azure\_search\_throttled\_queries\_rate\_id](#output\_azure\_search\_throttled\_queries\_rate\_id) | id for monitor azure\_search\_throttled\_queries\_rate | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure_app_services](https://docs.datadoghq.com/integrations/azure_app_services) + +Azure Documentation [https://docs.microsoft.com/en-us/azure/search/search-monitor-usage](https://docs.microsoft.com/en-us/azure/search/search-monitor-usage) + +Azure monitor metrics [https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-supported#microsoftsearchsearchservices](https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-supported#microsoftsearchsearchservices) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/azure-search/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/azure-search/inputs.tf new file mode 100755 index 0000000..ca0b277 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/azure-search/inputs.tf @@ -0,0 +1,132 @@ +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "azure_search_latency_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# Azure Search specific variables + +variable "latency_enabled" { + description = "Flag to enable Azure Search latency monitor" + type = string + default = "true" +} + +variable "latency_extra_tags" { + description = "Extra tags for Azure Search latency monitor" + type = list(string) + default = [] +} + +variable "latency_message" { + description = "Custom message for Azure Search latency monitor" + type = string + default = "" +} + +variable "latency_time_aggregator" { + description = "Monitor aggregator for Azure Search latency [available values: min, max or avg]" + type = string + default = "min" +} + +variable "latency_timeframe" { + description = "Monitor timeframe for Azure Search latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "latency_threshold_critical" { + default = 4 + description = "Alerting threshold for Azure Search latency in seconds" +} + +variable "latency_threshold_warning" { + default = 2 + description = "Warning threshold for Azure Search latency in seconds" +} + +variable "throttled_queries_rate_enabled" { + description = "Flag to enable Azure Search throttled queries rate monitor" + type = string + default = "true" +} + +variable "throttled_queries_rate_extra_tags" { + description = "Extra tags for Azure Search throttled queries rate monitor" + type = list(string) + default = [] +} + +variable "throttled_queries_rate_message" { + description = "Custom message for Azure Search throttled queries rate monitor" + type = string + default = "" +} + +variable "throttled_queries_rate_time_aggregator" { + description = "Monitor aggregator for Azure Search throttled queries rate [available values: min, max or avg]" + type = string + default = "min" +} + +variable "throttled_queries_rate_timeframe" { + description = "Monitor timeframe for Azure Search throttled queries rate [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "throttled_queries_rate_threshold_critical" { + default = 50 + description = "Alerting threshold for Azure Search throttled queries rate" +} + +variable "throttled_queries_rate_threshold_warning" { + default = 25 + description = "Warning threshold for Azure Search throttled queries rate" +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/azure-search/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/azure-search/modules.tf new file mode 100755 index 0000000..27f1095 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/azure-search/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_search" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/azure-search/monitors-azure-search.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/azure-search/monitors-azure-search.tf new file mode 100755 index 0000000..5788f48 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/azure-search/monitors-azure-search.tf @@ -0,0 +1,59 @@ +# Monitoring Azure Search latency +resource "datadog_monitor" "azure_search_latency" { + count = var.latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Search latency too high {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + message = coalesce(var.latency_message, var.message) + type = "query alert" + + query = < ${var.latency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.latency_threshold_warning + critical = var.latency_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = var.notify_no_data + no_data_timeframe = var.azure_search_latency_no_data_timeframe + renotify_interval = 0 + require_full_window = false + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:azure-search", "team:claranet", "created-by:terraform"], var.latency_extra_tags) +} + +# Monitoring Azure Search throttled queries +resource "datadog_monitor" "azure_search_throttled_queries_rate" { + count = var.throttled_queries_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Search throttled queries rate is too high {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + message = coalesce(var.throttled_queries_rate_message, var.message) + type = "query alert" + + query = < ${var.throttled_queries_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.throttled_queries_rate_threshold_warning + critical = var.throttled_queries_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:azure-search", "team:claranet", "created-by:terraform"], var.throttled_queries_rate_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/azure-search/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/azure-search/outputs.tf new file mode 100755 index 0000000..c4e9e54 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/azure-search/outputs.tf @@ -0,0 +1,10 @@ +output "azure_search_latency_id" { + description = "id for monitor azure_search_latency" + value = datadog_monitor.azure_search_latency.*.id +} + +output "azure_search_throttled_queries_rate_id" { + description = "id for monitor azure_search_throttled_queries_rate" + value = datadog_monitor.azure_search_throttled_queries_rate.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/azure-search/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/azure-search/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/azure-search/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/cosmosdb/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/cosmosdb/README.md new file mode 100755 index 0000000..3db2e4b --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/cosmosdb/README.md @@ -0,0 +1,110 @@ +# CLOUD AZURE COSMOSDB DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-cosmosdb" { + source = "claranet/monitors/datadog//cloud/azure/cosmosdb" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Cosmos DB 4xx requests rate is high +- Cosmos DB 5xx requests rate is high +- Cosmos DB is down +- Cosmos DB max scaling reached for collection + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | +| [filter-tags-statuscode](#module\_filter-tags-statuscode) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cosmos_db_4xx_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.cosmos_db_5xx_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.cosmos_db_scaling](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.cosmos_db_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cosmos\_db\_4xx\_request\_extra\_tags](#input\_cosmos\_db\_4xx\_request\_extra\_tags) | Extra tags for Cosmos DB 4xx requests monitor | `list(string)` | `[]` | no | +| [cosmos\_db\_4xx\_request\_rate\_threshold\_critical](#input\_cosmos\_db\_4xx\_request\_rate\_threshold\_critical) | Critical threshold for Cosmos DB 4xx requests monitor | `number` | `80` | no | +| [cosmos\_db\_4xx\_request\_rate\_threshold\_warning](#input\_cosmos\_db\_4xx\_request\_rate\_threshold\_warning) | Warning threshold for Cosmos DB 4xx requests monitor | `number` | `50` | no | +| [cosmos\_db\_4xx\_request\_time\_aggregator](#input\_cosmos\_db\_4xx\_request\_time\_aggregator) | Monitor aggregator for Cosmos DB 4xx requests [available values: min, max or avg] | `string` | `"min"` | no | +| [cosmos\_db\_4xx\_request\_timeframe](#input\_cosmos\_db\_4xx\_request\_timeframe) | Monitor timeframe for Cosmos DB 4xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [cosmos\_db\_4xx\_requests\_enabled](#input\_cosmos\_db\_4xx\_requests\_enabled) | Flag to enable Cosmos DB 4xx requests monitor | `string` | `"true"` | no | +| [cosmos\_db\_4xx\_requests\_message](#input\_cosmos\_db\_4xx\_requests\_message) | Custom message for Cosmos DB 4xx requests monitor | `string` | `""` | no | +| [cosmos\_db\_5xx\_request\_rate\_extra\_tags](#input\_cosmos\_db\_5xx\_request\_rate\_extra\_tags) | Extra tags for Cosmos DB 5xx requests monitor | `list(string)` | `[]` | no | +| [cosmos\_db\_5xx\_request\_rate\_threshold\_critical](#input\_cosmos\_db\_5xx\_request\_rate\_threshold\_critical) | Critical threshold for Cosmos DB 5xx requests monitor | `number` | `80` | no | +| [cosmos\_db\_5xx\_request\_rate\_threshold\_warning](#input\_cosmos\_db\_5xx\_request\_rate\_threshold\_warning) | Warning threshold for Cosmos DB 5xx requests monitor | `number` | `50` | no | +| [cosmos\_db\_5xx\_request\_time\_aggregator](#input\_cosmos\_db\_5xx\_request\_time\_aggregator) | Monitor aggregator for Cosmos DB 5xx requests [available values: min, max or avg] | `string` | `"min"` | no | +| [cosmos\_db\_5xx\_request\_timeframe](#input\_cosmos\_db\_5xx\_request\_timeframe) | Monitor timeframe for Cosmos DB 5xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [cosmos\_db\_5xx\_requests\_enabled](#input\_cosmos\_db\_5xx\_requests\_enabled) | Flag to enable Cosmos DB 5xx requests monitor | `string` | `"true"` | no | +| [cosmos\_db\_5xx\_requests\_message](#input\_cosmos\_db\_5xx\_requests\_message) | Custom message for Cosmos DB 5xx requests monitor | `string` | `""` | no | +| [cosmos\_db\_scaling\_enabled](#input\_cosmos\_db\_scaling\_enabled) | Flag to enable Cosmos DB scaling monitor | `string` | `"true"` | no | +| [cosmos\_db\_scaling\_error\_rate\_threshold\_critical](#input\_cosmos\_db\_scaling\_error\_rate\_threshold\_critical) | Critical threshold for Cosmos DB scaling monitor | `number` | `10` | no | +| [cosmos\_db\_scaling\_error\_rate\_threshold\_warning](#input\_cosmos\_db\_scaling\_error\_rate\_threshold\_warning) | Warning threshold for Cosmos DB scaling monitor | `number` | `5` | no | +| [cosmos\_db\_scaling\_extra\_tags](#input\_cosmos\_db\_scaling\_extra\_tags) | Extra tags for Cosmos DB scaling monitor | `list(string)` | `[]` | no | +| [cosmos\_db\_scaling\_message](#input\_cosmos\_db\_scaling\_message) | Custom message for Cosmos DB scaling monitor | `string` | `""` | no | +| [cosmos\_db\_scaling\_time\_aggregator](#input\_cosmos\_db\_scaling\_time\_aggregator) | Monitor aggregator for Cosmos DB scaling [available values: min, max or avg] | `string` | `"min"` | no | +| [cosmos\_db\_scaling\_timeframe](#input\_cosmos\_db\_scaling\_timeframe) | Monitor timeframe for Cosmos DB scaling [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [cosmos\_db\_status\_no\_data\_timeframe](#input\_cosmos\_db\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable Cosmos DB status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for Cosmos DB status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for Cosmos DB status monitor | `string` | `""` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for Cosmos DB status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for Cosmos DB status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cosmos\_db\_4xx\_requests\_id](#output\_cosmos\_db\_4xx\_requests\_id) | id for monitor cosmos\_db\_4xx\_requests | +| [cosmos\_db\_5xx\_requests\_id](#output\_cosmos\_db\_5xx\_requests\_id) | id for monitor cosmos\_db\_5xx\_requests | +| [cosmos\_db\_scaling\_id](#output\_cosmos\_db\_scaling\_id) | id for monitor cosmos\_db\_scaling | +| [cosmos\_db\_status\_id](#output\_cosmos\_db\_status\_id) | id for monitor cosmos\_db\_status | +## Related documentation + +DataDog documentation : [https://docs.datadoghq.com/integrations/azure/](https://docs.datadoghq.com/integrations/azure/) +You must search `cosmosdb`, there is no integration for now. + +Azure metrics documentation : [https://docs.microsoft.com/fr-fr/azure/monitoring-and-diagnostics/monitoring-supported-metrics#microsoftdocumentdbdatabaseaccounts](https://docs.microsoft.com/fr-fr/azure/monitoring-and-diagnostics/monitoring-supported-metrics#microsoftdocumentdbdatabaseaccounts) + +429 status code : [https://docs.microsoft.com/en-us/rest/api/cosmos-db/http-status-codes-for-cosmosdb](https://docs.microsoft.com/en-us/rest/api/cosmos-db/http-status-codes-for-cosmosdb) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/cosmosdb/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/cosmosdb/inputs.tf new file mode 100755 index 0000000..585a764 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/cosmosdb/inputs.tf @@ -0,0 +1,201 @@ +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "cosmos_db_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# Azure CosmosDB specific variables +variable "status_enabled" { + description = "Flag to enable Cosmos DB status monitor" + type = string + default = "true" +} + +variable "status_extra_tags" { + description = "Extra tags for Cosmos DB status monitor" + type = list(string) + default = [] +} + +variable "status_message" { + description = "Custom message for Cosmos DB status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for Cosmos DB status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for Cosmos DB status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "cosmos_db_4xx_requests_message" { + description = "Custom message for Cosmos DB 4xx requests monitor" + type = string + default = "" +} + +variable "cosmos_db_4xx_requests_enabled" { + description = "Flag to enable Cosmos DB 4xx requests monitor" + type = string + default = "true" +} + +variable "cosmos_db_4xx_request_rate_threshold_critical" { + description = "Critical threshold for Cosmos DB 4xx requests monitor" + default = 80 +} + +variable "cosmos_db_4xx_request_rate_threshold_warning" { + description = "Warning threshold for Cosmos DB 4xx requests monitor" + default = 50 +} + +variable "cosmos_db_4xx_request_extra_tags" { + description = "Extra tags for Cosmos DB 4xx requests monitor" + type = list(string) + default = [] +} + +variable "cosmos_db_4xx_request_time_aggregator" { + description = "Monitor aggregator for Cosmos DB 4xx requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cosmos_db_4xx_request_timeframe" { + description = "Monitor timeframe for Cosmos DB 4xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "cosmos_db_5xx_requests_message" { + description = "Custom message for Cosmos DB 5xx requests monitor" + type = string + default = "" +} + +variable "cosmos_db_5xx_requests_enabled" { + description = "Flag to enable Cosmos DB 5xx requests monitor" + type = string + default = "true" +} + +variable "cosmos_db_5xx_request_rate_threshold_critical" { + description = "Critical threshold for Cosmos DB 5xx requests monitor" + default = 80 +} + +variable "cosmos_db_5xx_request_rate_threshold_warning" { + description = "Warning threshold for Cosmos DB 5xx requests monitor" + default = 50 +} + +variable "cosmos_db_5xx_request_rate_extra_tags" { + description = "Extra tags for Cosmos DB 5xx requests monitor" + type = list(string) + default = [] +} + +variable "cosmos_db_5xx_request_time_aggregator" { + description = "Monitor aggregator for Cosmos DB 5xx requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cosmos_db_5xx_request_timeframe" { + description = "Monitor timeframe for Cosmos DB 5xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "cosmos_db_scaling_message" { + description = "Custom message for Cosmos DB scaling monitor" + type = string + default = "" +} + +variable "cosmos_db_scaling_enabled" { + description = "Flag to enable Cosmos DB scaling monitor" + type = string + default = "true" +} + +variable "cosmos_db_scaling_error_rate_threshold_critical" { + description = "Critical threshold for Cosmos DB scaling monitor" + default = 10 +} + +variable "cosmos_db_scaling_error_rate_threshold_warning" { + description = "Warning threshold for Cosmos DB scaling monitor" + default = 5 +} + +variable "cosmos_db_scaling_extra_tags" { + description = "Extra tags for Cosmos DB scaling monitor" + type = list(string) + default = [] +} + +variable "cosmos_db_scaling_time_aggregator" { + description = "Monitor aggregator for Cosmos DB scaling [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cosmos_db_scaling_timeframe" { + description = "Monitor timeframe for Cosmos DB scaling [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/cosmosdb/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/cosmosdb/modules.tf new file mode 100755 index 0000000..d54aaf2 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/cosmosdb/modules.tf @@ -0,0 +1,21 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_cosmosdb" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + +module "filter-tags-statuscode" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_cosmosdb" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["statuscode:%s"] +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/cosmosdb/monitors-cosmosdb.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/cosmosdb/monitors-cosmosdb.tf new file mode 100755 index 0000000..fee4748 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/cosmosdb/monitors-cosmosdb.tf @@ -0,0 +1,135 @@ +resource "datadog_monitor" "cosmos_db_status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Cosmos DB is down" + message = coalesce(var.status_message, var.message) + type = "metric alert" + + query = < ${var.cosmos_db_4xx_request_rate_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.cosmos_db_4xx_request_rate_threshold_critical + warning = var.cosmos_db_4xx_request_rate_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:cosmos_db", "team:claranet", "created-by:terraform"], var.cosmos_db_4xx_request_extra_tags) +} + +resource "datadog_monitor" "cosmos_db_5xx_requests" { + count = var.cosmos_db_5xx_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Cosmos DB 5xx requests rate is high {{#is_alert}}{{comparator}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{comparator}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cosmos_db_5xx_requests_message, var.message) + type = "query alert" + + query = < ${var.cosmos_db_5xx_request_rate_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.cosmos_db_5xx_request_rate_threshold_critical + warning = var.cosmos_db_5xx_request_rate_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:cosmos_db", "team:claranet", "created-by:terraform"], var.cosmos_db_5xx_request_rate_extra_tags) +} + +resource "datadog_monitor" "cosmos_db_scaling" { + count = var.cosmos_db_scaling_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Cosmos DB max scaling reached for collection {{#is_alert}}{{comparator}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{comparator}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cosmos_db_scaling_message, var.message) + type = "query alert" + + # List of available status codes : https://docs.microsoft.com/en-us/rest/api/cosmos-db/http-status-codes-for-cosmosdb + query = < ${var.cosmos_db_scaling_error_rate_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.cosmos_db_scaling_error_rate_threshold_critical + warning = var.cosmos_db_scaling_error_rate_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:cosmos_db", "team:claranet", "created-by:terraform"], var.cosmos_db_scaling_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/cosmosdb/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/cosmosdb/outputs.tf new file mode 100755 index 0000000..7958283 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/cosmosdb/outputs.tf @@ -0,0 +1,20 @@ +output "cosmos_db_4xx_requests_id" { + description = "id for monitor cosmos_db_4xx_requests" + value = datadog_monitor.cosmos_db_4xx_requests.*.id +} + +output "cosmos_db_5xx_requests_id" { + description = "id for monitor cosmos_db_5xx_requests" + value = datadog_monitor.cosmos_db_5xx_requests.*.id +} + +output "cosmos_db_scaling_id" { + description = "id for monitor cosmos_db_scaling" + value = datadog_monitor.cosmos_db_scaling.*.id +} + +output "cosmos_db_status_id" { + description = "id for monitor cosmos_db_status" + value = datadog_monitor.cosmos_db_status.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/cosmosdb/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/cosmosdb/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/cosmosdb/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/datalakestore/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/datalakestore/README.md new file mode 100755 index 0000000..180af1a --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/datalakestore/README.md @@ -0,0 +1,77 @@ +# CLOUD AZURE DATALAKESTORE DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-datalakestore" { + source = "claranet/monitors/datadog//cloud/azure/datalakestore" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Datalake Store is down + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.datalakestore_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [datalakestore\_status\_no\_data\_timeframe](#input\_datalakestore\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable Datalake Store status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for Datalake Store status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for Datalake Store status monitor | `string` | `""` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for Datalake Store status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for Datalake Store status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [datalakestore\_status\_id](#output\_datalakestore\_status\_id) | id for monitor datalakestore\_status | +## Related documentation + +DataDog documentation : [https://docs.datadoghq.com/integrations/azure/](https://docs.datadoghq.com/integrations/azure/) +You must search `datalake`, there is no integration for now. + +Azure metrics documentation : [https://docs.microsoft.com/fr-fr/azure/monitoring-and-diagnostics/monitoring-supported-metrics#microsoftdatalakestoreaccounts](https://docs.microsoft.com/fr-fr/azure/monitoring-and-diagnostics/monitoring-supported-metrics#microsoftdatalakestoreaccounts) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/datalakestore/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/datalakestore/inputs.tf new file mode 100755 index 0000000..ba4e314 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/datalakestore/inputs.tf @@ -0,0 +1,80 @@ +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "datalakestore_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# Azure Datalake Store specific variables +variable "status_enabled" { + description = "Flag to enable Datalake Store status monitor" + type = string + default = "true" +} + +variable "status_message" { + description = "Custom message for Datalake Store status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for Datalake Store status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for Datalake Store status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + default = "last_5m" +} + +variable "status_extra_tags" { + description = "Extra tags for Datalake Store status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/datalakestore/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/datalakestore/modules.tf new file mode 100755 index 0000000..b837d67 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/datalakestore/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_datalakestore" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/datalakestore/monitors-datalakestore.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/datalakestore/monitors-datalakestore.tf new file mode 100755 index 0000000..0d8fa42 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/datalakestore/monitors-datalakestore.tf @@ -0,0 +1,26 @@ +resource "datadog_monitor" "datalakestore_status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Datalake Store is down" + message = coalesce(var.status_message, var.message) + type = "query alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.eventgrid_failed_messages](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.eventgrid_no_successful_message](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.eventgrid_unmatched_events](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [eventgrid\_no\_successful\_message\_no\_data\_timeframe](#input\_eventgrid\_no\_successful\_message\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [failed\_messages\_rate\_enabled](#input\_failed\_messages\_rate\_enabled) | Flag to enable Event Grid failed messages monitor | `string` | `"true"` | no | +| [failed\_messages\_rate\_extra\_tags](#input\_failed\_messages\_rate\_extra\_tags) | Extra tags for Event Grid failed messages monitor | `list(string)` | `[]` | no | +| [failed\_messages\_rate\_message](#input\_failed\_messages\_rate\_message) | Custom message for Event Grid failed messages monitor | `string` | `""` | no | +| [failed\_messages\_rate\_thresold\_critical](#input\_failed\_messages\_rate\_thresold\_critical) | Failed messages ratio (percentage) to trigger the critical alert | `number` | `90` | no | +| [failed\_messages\_rate\_thresold\_warning](#input\_failed\_messages\_rate\_thresold\_warning) | Failed messages ratio (percentage) to trigger a warning alert | `number` | `50` | no | +| [failed\_messages\_rate\_time\_aggregator](#input\_failed\_messages\_rate\_time\_aggregator) | Monitor aggregator for Event Grid failed messages [available values: min, max or avg] | `string` | `"min"` | no | +| [failed\_messages\_rate\_timeframe](#input\_failed\_messages\_rate\_timeframe) | Monitor timeframe for Event Grid failed messages [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [no\_successful\_message\_rate\_enabled](#input\_no\_successful\_message\_rate\_enabled) | Flag to enable Event Grid no successful message monitor | `string` | `"true"` | no | +| [no\_successful\_message\_rate\_extra\_tags](#input\_no\_successful\_message\_rate\_extra\_tags) | Extra tags for Event Grid no successful message monitor | `list(string)` | `[]` | no | +| [no\_successful\_message\_rate\_message](#input\_no\_successful\_message\_rate\_message) | Custom message for Event Grid no successful message monitor | `string` | `""` | no | +| [no\_successful\_message\_rate\_time\_aggregator](#input\_no\_successful\_message\_rate\_time\_aggregator) | Monitor aggregator for Event Grid no successful message [available values: min, max or avg] | `string` | `"min"` | no | +| [no\_successful\_message\_rate\_timeframe](#input\_no\_successful\_message\_rate\_timeframe) | Monitor timeframe for Event Grid no successful message [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [unmatched\_events\_rate\_enabled](#input\_unmatched\_events\_rate\_enabled) | Flag to enable Event Grid unmatched events monitor | `string` | `"true"` | no | +| [unmatched\_events\_rate\_extra\_tags](#input\_unmatched\_events\_rate\_extra\_tags) | Extra tags for Event Grid unmatched events monitor | `list(string)` | `[]` | no | +| [unmatched\_events\_rate\_message](#input\_unmatched\_events\_rate\_message) | Custom message for Event Grid unmatched events monitor | `string` | `""` | no | +| [unmatched\_events\_rate\_thresold\_critical](#input\_unmatched\_events\_rate\_thresold\_critical) | Unmatched events ratio (percentage) to trigger the critical alert | `number` | `90` | no | +| [unmatched\_events\_rate\_thresold\_warning](#input\_unmatched\_events\_rate\_thresold\_warning) | Unmatched events ratio (percentage) to trigger a warning alert | `number` | `50` | no | +| [unmatched\_events\_rate\_time\_aggregator](#input\_unmatched\_events\_rate\_time\_aggregator) | Monitor aggregator for Event Grid unmatched events [available values: min, max or avg] | `string` | `"min"` | no | +| [unmatched\_events\_rate\_timeframe](#input\_unmatched\_events\_rate\_timeframe) | Monitor timeframe for Event Grid unmatched events [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [eventgrid\_failed\_messages\_id](#output\_eventgrid\_failed\_messages\_id) | id for monitor eventgrid\_failed\_messages | +| [eventgrid\_no\_successful\_message\_id](#output\_eventgrid\_no\_successful\_message\_id) | id for monitor eventgrid\_no\_successful\_message | +| [eventgrid\_unmatched\_events\_id](#output\_eventgrid\_unmatched\_events\_id) | id for monitor eventgrid\_unmatched\_events | +## Related documentation + +Datadog Azure documentation: [https://docs.datadoghq.com/integrations/azure/](https://docs.datadoghq.com/integrations/azure/) + +Azure "Monitor event delivery" documentation: [https://docs.microsoft.com/en-us/azure/event-grid/monitor-event-delivery](https://docs.microsoft.com/en-us/azure/event-grid/monitor-event-delivery) + +Azure Monitor metrics: [https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-supported#microsofteventgridtopics](https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-supported#microsofteventgridtopics) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventgrid/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventgrid/inputs.tf new file mode 100755 index 0000000..61c7693 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventgrid/inputs.tf @@ -0,0 +1,164 @@ +# Global Terraform +variable "environment" { + description = "Architecture environment" + type = string +} + +# Global DataDog +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "eventgrid_no_successful_message_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Azure Event Grid specific variables + +variable "no_successful_message_rate_enabled" { + description = "Flag to enable Event Grid no successful message monitor" + type = string + default = "true" +} + +variable "no_successful_message_rate_extra_tags" { + description = "Extra tags for Event Grid no successful message monitor" + type = list(string) + default = [] +} + +variable "no_successful_message_rate_message" { + description = "Custom message for Event Grid no successful message monitor" + type = string + default = "" +} + +variable "no_successful_message_rate_time_aggregator" { + description = "Monitor aggregator for Event Grid no successful message [available values: min, max or avg]" + type = string + default = "min" +} + +variable "no_successful_message_rate_timeframe" { + description = "Monitor timeframe for Event Grid no successful message [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_messages_rate_enabled" { + description = "Flag to enable Event Grid failed messages monitor" + type = string + default = "true" +} + +variable "failed_messages_rate_extra_tags" { + description = "Extra tags for Event Grid failed messages monitor" + type = list(string) + default = [] +} + +variable "failed_messages_rate_message" { + description = "Custom message for Event Grid failed messages monitor" + type = string + default = "" +} + +variable "failed_messages_rate_time_aggregator" { + description = "Monitor aggregator for Event Grid failed messages [available values: min, max or avg]" + type = string + default = "min" +} + +variable "failed_messages_rate_timeframe" { + description = "Monitor timeframe for Event Grid failed messages [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_messages_rate_thresold_critical" { + description = "Failed messages ratio (percentage) to trigger the critical alert" + default = 90 +} + +variable "failed_messages_rate_thresold_warning" { + description = "Failed messages ratio (percentage) to trigger a warning alert" + default = 50 +} + +variable "unmatched_events_rate_enabled" { + description = "Flag to enable Event Grid unmatched events monitor" + type = string + default = "true" +} + +variable "unmatched_events_rate_extra_tags" { + description = "Extra tags for Event Grid unmatched events monitor" + type = list(string) + default = [] +} + +variable "unmatched_events_rate_message" { + description = "Custom message for Event Grid unmatched events monitor" + type = string + default = "" +} + +variable "unmatched_events_rate_time_aggregator" { + description = "Monitor aggregator for Event Grid unmatched events [available values: min, max or avg]" + type = string + default = "min" +} + +variable "unmatched_events_rate_timeframe" { + description = "Monitor timeframe for Event Grid unmatched events [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "unmatched_events_rate_thresold_critical" { + description = "Unmatched events ratio (percentage) to trigger the critical alert" + default = 90 +} + +variable "unmatched_events_rate_thresold_warning" { + description = "Unmatched events ratio (percentage) to trigger a warning alert" + default = 50 +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventgrid/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventgrid/modules.tf new file mode 100755 index 0000000..2127f87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventgrid/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "eventgrid" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventgrid/monitors-eventgrid.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventgrid/monitors-eventgrid.tf new file mode 100755 index 0000000..efe5402 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventgrid/monitors-eventgrid.tf @@ -0,0 +1,94 @@ +resource "datadog_monitor" "eventgrid_no_successful_message" { + count = var.no_successful_message_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Event Grid no successful message {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.no_successful_message_rate_message, var.message) + type = "metric alert" + + # Query is a bit weird, but we only want to check the no-data + query = < ${var.failed_messages_rate_thresold_critical} +EOQ + + monitor_thresholds { + critical = var.failed_messages_rate_thresold_critical + warning = var.failed_messages_rate_thresold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:eventgrid", "team:claranet", "created-by:terraform"], var.failed_messages_rate_extra_tags) +} + +resource "datadog_monitor" "eventgrid_unmatched_events" { + count = var.unmatched_events_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Event Grid too many unmatched events {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.unmatched_events_rate_message, var.message) + type = "query alert" + + query = < ${var.unmatched_events_rate_thresold_critical} +EOQ + + monitor_thresholds { + critical = var.unmatched_events_rate_thresold_critical + warning = var.unmatched_events_rate_thresold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:eventgrid", "team:claranet", "created-by:terraform"], var.unmatched_events_rate_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventgrid/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventgrid/outputs.tf new file mode 100755 index 0000000..7c58008 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventgrid/outputs.tf @@ -0,0 +1,15 @@ +output "eventgrid_failed_messages_id" { + description = "id for monitor eventgrid_failed_messages" + value = datadog_monitor.eventgrid_failed_messages.*.id +} + +output "eventgrid_no_successful_message_id" { + description = "id for monitor eventgrid_no_successful_message" + value = datadog_monitor.eventgrid_no_successful_message.*.id +} + +output "eventgrid_unmatched_events_id" { + description = "id for monitor eventgrid_unmatched_events" + value = datadog_monitor.eventgrid_unmatched_events.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventgrid/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventgrid/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventgrid/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventhub/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventhub/README.md new file mode 100755 index 0000000..264e0d3 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventhub/README.md @@ -0,0 +1,96 @@ +# CLOUD AZURE EVENTHUB DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-eventhub" { + source = "claranet/monitors/datadog//cloud/azure/eventhub" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Event Hub is down +- Event Hub too many errors +- Event Hub too many failed requests + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.eventhub_errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.eventhub_failed_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.eventhub_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [errors\_rate\_enabled](#input\_errors\_rate\_enabled) | Flag to enable Event Hub errors monitor | `string` | `"true"` | no | +| [errors\_rate\_extra\_tags](#input\_errors\_rate\_extra\_tags) | Extra tags for Event Hub errors monitor | `list(string)` | `[]` | no | +| [errors\_rate\_message](#input\_errors\_rate\_message) | Custom message for Event Hub errors monitor | `string` | `""` | no | +| [errors\_rate\_thresold\_critical](#input\_errors\_rate\_thresold\_critical) | Errors ratio (percentage) to trigger the critical alert | `number` | `90` | no | +| [errors\_rate\_thresold\_warning](#input\_errors\_rate\_thresold\_warning) | Errors ratio (percentage) to trigger a warning alert | `number` | `50` | no | +| [errors\_rate\_time\_aggregator](#input\_errors\_rate\_time\_aggregator) | Monitor aggregator for Event Hub errors [available values: min, max or avg] | `string` | `"min"` | no | +| [errors\_rate\_timeframe](#input\_errors\_rate\_timeframe) | Monitor timeframe for Event Hub errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [eventhub\_status\_no\_data\_timeframe](#input\_eventhub\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [failed\_requests\_rate\_enabled](#input\_failed\_requests\_rate\_enabled) | Flag to enable Event Hub failed requests monitor | `string` | `"true"` | no | +| [failed\_requests\_rate\_extra\_tags](#input\_failed\_requests\_rate\_extra\_tags) | Extra tags for Event Hub failed requests monitor | `list(string)` | `[]` | no | +| [failed\_requests\_rate\_message](#input\_failed\_requests\_rate\_message) | Custom message for Event Hub failed requests monitor | `string` | `""` | no | +| [failed\_requests\_rate\_thresold\_critical](#input\_failed\_requests\_rate\_thresold\_critical) | Failed requests ratio (percentage) to trigger the critical alert | `number` | `90` | no | +| [failed\_requests\_rate\_thresold\_warning](#input\_failed\_requests\_rate\_thresold\_warning) | Failed requests ratio (percentage) to trigger a warning alert | `number` | `50` | no | +| [failed\_requests\_rate\_time\_aggregator](#input\_failed\_requests\_rate\_time\_aggregator) | Monitor aggregator for Event Hub failed requests [available values: min, max or avg] | `string` | `"min"` | no | +| [failed\_requests\_rate\_timeframe](#input\_failed\_requests\_rate\_timeframe) | Monitor timeframe for Event Hub failed requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable Event Hub status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for Event Hub status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for Event Hub status monitor | `string` | `""` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for Event Hub status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for Event Hub status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [eventhub\_errors\_id](#output\_eventhub\_errors\_id) | id for monitor eventhub\_errors | +| [eventhub\_failed\_requests\_id](#output\_eventhub\_failed\_requests\_id) | id for monitor eventhub\_failed\_requests | +| [eventhub\_status\_id](#output\_eventhub\_status\_id) | id for monitor eventhub\_status | +## Related documentation + +Datadog documentation : [https://docs.datadoghq.com/integrations/azure_event_hub/](https://docs.datadoghq.com/integrations/azure_event_hub/) + +Azure metrics documentation : [https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-metrics-azure-monitor](https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-metrics-azure-monitor) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventhub/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventhub/inputs.tf new file mode 100755 index 0000000..bcc9797 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventhub/inputs.tf @@ -0,0 +1,164 @@ +# Global Terraform +variable "environment" { + description = "Architecture environment" + type = string +} + +# Global DataDog +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "eventhub_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Azure Event Hub specific variables + +variable "status_enabled" { + description = "Flag to enable Event Hub status monitor" + type = string + default = "true" +} + +variable "status_extra_tags" { + description = "Extra tags for Event Hub status monitor" + type = list(string) + default = [] +} + +variable "status_message" { + description = "Custom message for Event Hub status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for Event Hub status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for Event Hub status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_requests_rate_enabled" { + description = "Flag to enable Event Hub failed requests monitor" + type = string + default = "true" +} + +variable "failed_requests_rate_extra_tags" { + description = "Extra tags for Event Hub failed requests monitor" + type = list(string) + default = [] +} + +variable "failed_requests_rate_message" { + description = "Custom message for Event Hub failed requests monitor" + type = string + default = "" +} + +variable "failed_requests_rate_time_aggregator" { + description = "Monitor aggregator for Event Hub failed requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "failed_requests_rate_timeframe" { + description = "Monitor timeframe for Event Hub failed requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_requests_rate_thresold_critical" { + description = "Failed requests ratio (percentage) to trigger the critical alert" + default = 90 +} + +variable "failed_requests_rate_thresold_warning" { + description = "Failed requests ratio (percentage) to trigger a warning alert" + default = 50 +} + +variable "errors_rate_enabled" { + description = "Flag to enable Event Hub errors monitor" + type = string + default = "true" +} + +variable "errors_rate_extra_tags" { + description = "Extra tags for Event Hub errors monitor" + type = list(string) + default = [] +} + +variable "errors_rate_message" { + description = "Custom message for Event Hub errors monitor" + type = string + default = "" +} + +variable "errors_rate_time_aggregator" { + description = "Monitor aggregator for Event Hub errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "errors_rate_timeframe" { + description = "Monitor timeframe for Event Hub errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "errors_rate_thresold_critical" { + description = "Errors ratio (percentage) to trigger the critical alert" + default = 90 +} + +variable "errors_rate_thresold_warning" { + description = "Errors ratio (percentage) to trigger a warning alert" + default = 50 +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventhub/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventhub/modules.tf new file mode 100755 index 0000000..15b8884 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventhub/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_eventhub" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventhub/monitors-eventhub.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventhub/monitors-eventhub.tf new file mode 100755 index 0000000..caa6321 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventhub/monitors-eventhub.tf @@ -0,0 +1,90 @@ +resource "datadog_monitor" "eventhub_status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Event Hub is down" + message = coalesce(var.status_message, var.message) + type = "query alert" + + query = < ${var.failed_requests_rate_thresold_critical} +EOQ + + monitor_thresholds { + critical = var.failed_requests_rate_thresold_critical + warning = var.failed_requests_rate_thresold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:eventhub", "team:claranet", "created-by:terraform"], var.failed_requests_rate_extra_tags) +} + +resource "datadog_monitor" "eventhub_errors" { + count = var.errors_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Event Hub too many errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.errors_rate_message, var.message) + type = "query alert" + + query = < ${var.errors_rate_thresold_critical} +EOQ + + monitor_thresholds { + critical = var.errors_rate_thresold_critical + warning = var.errors_rate_thresold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:eventhub", "team:claranet", "created-by:terraform"], var.errors_rate_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventhub/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventhub/outputs.tf new file mode 100755 index 0000000..94646a5 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventhub/outputs.tf @@ -0,0 +1,15 @@ +output "eventhub_errors_id" { + description = "id for monitor eventhub_errors" + value = datadog_monitor.eventhub_errors.*.id +} + +output "eventhub_failed_requests_id" { + description = "id for monitor eventhub_failed_requests" + value = datadog_monitor.eventhub_failed_requests.*.id +} + +output "eventhub_status_id" { + description = "id for monitor eventhub_status" + value = datadog_monitor.eventhub_status.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventhub/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventhub/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/eventhub/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/functions/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/functions/README.md new file mode 100755 index 0000000..5b8bbdd --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/functions/README.md @@ -0,0 +1,99 @@ +# CLOUD AZURE FUNCTIONS DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-functions" { + source = "claranet/monitors/datadog//cloud/azure/functions" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Function App connections count too high +- Function App HTTP 5xx errors too high +- Function App threads count too high + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.function_high_connections_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.function_high_threads_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.function_http_5xx_errors_rate](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [high\_connections\_count\_enabled](#input\_high\_connections\_count\_enabled) | Flag to enable Functions high connections count monitor | `string` | `"true"` | no | +| [high\_connections\_count\_extra\_tags](#input\_high\_connections\_count\_extra\_tags) | Extra tags for Functions high connections count monitor | `list(string)` | `[]` | no | +| [high\_connections\_count\_message](#input\_high\_connections\_count\_message) | Custom message for Functions high connections count monitor | `string` | `""` | no | +| [high\_connections\_count\_threshold\_critical](#input\_high\_connections\_count\_threshold\_critical) | Alerting threshold for Functions high connections count | `number` | `590` | no | +| [high\_connections\_count\_threshold\_warning](#input\_high\_connections\_count\_threshold\_warning) | Warning threshold for Functions high connections count | `number` | `550` | no | +| [high\_connections\_count\_time\_aggregator](#input\_high\_connections\_count\_time\_aggregator) | Monitor aggregator for Functions high connections count [available values: min, max or avg] | `string` | `"min"` | no | +| [high\_connections\_count\_timeframe](#input\_high\_connections\_count\_timeframe) | Monitor timeframe for Functions high connections count [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [high\_threads\_count\_enabled](#input\_high\_threads\_count\_enabled) | Flag to enable Functions high threads count monitor | `string` | `"true"` | no | +| [high\_threads\_count\_extra\_tags](#input\_high\_threads\_count\_extra\_tags) | Extra tags for Functions high threads count monitor | `list(string)` | `[]` | no | +| [high\_threads\_count\_message](#input\_high\_threads\_count\_message) | Custom message for Functions high threads count monitor | `string` | `""` | no | +| [high\_threads\_count\_threshold\_critical](#input\_high\_threads\_count\_threshold\_critical) | Alerting threshold for Functions high threads count | `number` | `510` | no | +| [high\_threads\_count\_threshold\_warning](#input\_high\_threads\_count\_threshold\_warning) | Warning threshold for Functions high threads count | `number` | `490` | no | +| [high\_threads\_count\_time\_aggregator](#input\_high\_threads\_count\_time\_aggregator) | Monitor aggregator for Functions high threads count [available values: min, max or avg] | `string` | `"min"` | no | +| [high\_threads\_count\_timeframe](#input\_high\_threads\_count\_timeframe) | Monitor timeframe for Functions high threads count [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [http\_5xx\_errors\_rate\_enabled](#input\_http\_5xx\_errors\_rate\_enabled) | Flag to enable Functions Http 5xx errors rate monitor | `string` | `"true"` | no | +| [http\_5xx\_errors\_rate\_extra\_tags](#input\_http\_5xx\_errors\_rate\_extra\_tags) | Extra tags for Functions Http 5xx errors rate monitor | `list(string)` | `[]` | no | +| [http\_5xx\_errors\_rate\_message](#input\_http\_5xx\_errors\_rate\_message) | Custom message for Functions Http 5xx errors rate monitor | `string` | `""` | no | +| [http\_5xx\_errors\_rate\_threshold\_critical](#input\_http\_5xx\_errors\_rate\_threshold\_critical) | Alerting threshold for Functions Http 5xx errors rate | `number` | `20` | no | +| [http\_5xx\_errors\_rate\_threshold\_warning](#input\_http\_5xx\_errors\_rate\_threshold\_warning) | Warning threshold for Functions Http 5xx errors rate | `number` | `10` | no | +| [http\_5xx\_errors\_rate\_time\_aggregator](#input\_http\_5xx\_errors\_rate\_time\_aggregator) | Monitor aggregator for Functions Http 5xx errors rate [available values: min, max or avg] | `string` | `"min"` | no | +| [http\_5xx\_errors\_rate\_timeframe](#input\_http\_5xx\_errors\_rate\_timeframe) | Monitor timeframe for Functions Http 5xx errors rate [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [function\_high\_connections\_count\_id](#output\_function\_high\_connections\_count\_id) | id for monitor function\_high\_connections\_count | +| [function\_high\_threads\_count\_id](#output\_function\_high\_threads\_count\_id) | id for monitor function\_high\_threads\_count | +| [function\_http\_5xx\_errors\_rate\_id](#output\_function\_http\_5xx\_errors\_rate\_id) | id for monitor function\_http\_5xx\_errors\_rate | +## Related documentation + +Datadog Azure documentation: [https://docs.datadoghq.com/integrations/azure/](https://docs.datadoghq.com/integrations/azure/) + +Azure Monitor metrics: [https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-supported#microsoftwebsites-functions](https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-supported#microsoftwebsites-functions) + +Azure Functions connections limits: [https://docs.microsoft.com/en-us/azure/azure-functions/manage-connections#connections-limit](https://docs.microsoft.com/en-us/azure/azure-functions/manage-connections#connections-limit) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/functions/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/functions/inputs.tf new file mode 100755 index 0000000..2b76cec --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/functions/inputs.tf @@ -0,0 +1,166 @@ +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# Azure Function App specific variables + +variable "http_5xx_errors_rate_enabled" { + description = "Flag to enable Functions Http 5xx errors rate monitor" + type = string + default = "true" +} + +variable "http_5xx_errors_rate_extra_tags" { + description = "Extra tags for Functions Http 5xx errors rate monitor" + type = list(string) + default = [] +} + +variable "http_5xx_errors_rate_message" { + description = "Custom message for Functions Http 5xx errors rate monitor" + type = string + default = "" +} + +variable "http_5xx_errors_rate_time_aggregator" { + description = "Monitor aggregator for Functions Http 5xx errors rate [available values: min, max or avg]" + type = string + default = "min" +} + +variable "http_5xx_errors_rate_timeframe" { + description = "Monitor timeframe for Functions Http 5xx errors rate [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "http_5xx_errors_rate_threshold_critical" { + default = 20 + description = "Alerting threshold for Functions Http 5xx errors rate" +} + +variable "http_5xx_errors_rate_threshold_warning" { + default = 10 + description = "Warning threshold for Functions Http 5xx errors rate" +} + +variable "high_connections_count_enabled" { + description = "Flag to enable Functions high connections count monitor" + type = string + default = "true" +} + +variable "high_connections_count_extra_tags" { + description = "Extra tags for Functions high connections count monitor" + type = list(string) + default = [] +} + +variable "high_connections_count_message" { + description = "Custom message for Functions high connections count monitor" + type = string + default = "" +} + +variable "high_connections_count_time_aggregator" { + description = "Monitor aggregator for Functions high connections count [available values: min, max or avg]" + type = string + default = "min" +} + +variable "high_connections_count_timeframe" { + description = "Monitor timeframe for Functions high connections count [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "high_connections_count_threshold_critical" { + default = 590 + description = "Alerting threshold for Functions high connections count" +} + +variable "high_connections_count_threshold_warning" { + default = 550 + description = "Warning threshold for Functions high connections count" +} + +variable "high_threads_count_enabled" { + description = "Flag to enable Functions high threads count monitor" + type = string + default = "true" +} + +variable "high_threads_count_extra_tags" { + description = "Extra tags for Functions high threads count monitor" + type = list(string) + default = [] +} + +variable "high_threads_count_message" { + description = "Custom message for Functions high threads count monitor" + type = string + default = "" +} + +variable "high_threads_count_time_aggregator" { + description = "Monitor aggregator for Functions high threads count [available values: min, max or avg]" + type = string + default = "min" +} + +variable "high_threads_count_timeframe" { + description = "Monitor timeframe for Functions high threads count [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "high_threads_count_threshold_critical" { + default = 510 + description = "Alerting threshold for Functions high threads count" +} + +variable "high_threads_count_threshold_warning" { + default = 490 + description = "Warning threshold for Functions high threads count" +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/functions/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/functions/modules.tf new file mode 100755 index 0000000..8d6e1d0 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/functions/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_functions" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/functions/monitors-functions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/functions/monitors-functions.tf new file mode 100755 index 0000000..f54aa18 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/functions/monitors-functions.tf @@ -0,0 +1,85 @@ +resource "datadog_monitor" "function_http_5xx_errors_rate" { + count = var.http_5xx_errors_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Function App HTTP 5xx errors too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.http_5xx_errors_rate_message, var.message) + type = "query alert" + + query = < ${var.http_5xx_errors_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.http_5xx_errors_rate_threshold_warning + critical = var.http_5xx_errors_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 1 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:azure_functions", "team:claranet", "created-by:terraform"], var.http_5xx_errors_rate_extra_tags) +} + +resource "datadog_monitor" "function_high_connections_count" { + count = var.high_connections_count_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Function App connections count too high {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.high_connections_count_message, var.message) + type = "query alert" + + query = < ${var.high_connections_count_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.high_connections_count_threshold_warning + critical = var.high_connections_count_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 1 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:azure_functions", "team:claranet", "created-by:terraform"], var.high_connections_count_extra_tags) +} + +resource "datadog_monitor" "function_high_threads_count" { + count = var.high_threads_count_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Function App threads count too high {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.high_threads_count_message, var.message) + type = "query alert" + + query = < ${var.high_threads_count_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.high_threads_count_threshold_warning + critical = var.high_threads_count_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 1 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:azure_functions", "team:claranet", "created-by:terraform"], var.high_threads_count_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/functions/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/functions/outputs.tf new file mode 100755 index 0000000..60481dd --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/functions/outputs.tf @@ -0,0 +1,15 @@ +output "function_high_connections_count_id" { + description = "id for monitor function_high_connections_count" + value = datadog_monitor.function_high_connections_count.*.id +} + +output "function_high_threads_count_id" { + description = "id for monitor function_high_threads_count" + value = datadog_monitor.function_high_threads_count.*.id +} + +output "function_http_5xx_errors_rate_id" { + description = "id for monitor function_http_5xx_errors_rate" + value = datadog_monitor.function_http_5xx_errors_rate.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/functions/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/functions/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/functions/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/iothubs/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/iothubs/README.md new file mode 100755 index 0000000..c119288 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/iothubs/README.md @@ -0,0 +1,203 @@ +# CLOUD AZURE IOTHUBS DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-iothubs" { + source = "claranet/monitors/datadog//cloud/azure/iothubs" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- IOT Hub is down +- IOT Hub Too many c2d methods failure +- IOT Hub Too many c2d twin read failure +- IOT Hub Too many c2d twin update failure +- IOT Hub Too many d2c telemetry egress dropped +- IOT Hub Too many d2c telemetry egress invalid +- IOT Hub Too many d2c telemetry egress orphaned +- IOT Hub Too many d2c telemetry ingress not sent +- IOT Hub Too many d2c twin read failure +- IOT Hub Too many d2c twin update failure +- IOT Hub Too many jobs failed +- IOT Hub Too many list_jobs failure +- IOT Hub Too many query_jobs failed +- IOT Hub Total devices is wrong + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_c2d_methods_failed](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_c2d_twin_read_failed](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_c2d_twin_update_failed](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_d2c_telemetry_egress_dropped](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_d2c_telemetry_egress_invalid](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_d2c_telemetry_egress_orphaned](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_d2c_telemetry_ingress_nosent](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_d2c_twin_read_failed](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_d2c_twin_update_failed](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_jobs_failed](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_list_jobs_failed](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_query_jobs_failed](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.total_devices](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [dropped\_d2c\_telemetry\_egress\_enabled](#input\_dropped\_d2c\_telemetry\_egress\_enabled) | Flag to enable IoT Hub dropped d2c telemetry monitor | `string` | `"true"` | no | +| [dropped\_d2c\_telemetry\_egress\_extra\_tags](#input\_dropped\_d2c\_telemetry\_egress\_extra\_tags) | Extra tags for IoT Hub dropped d2c telemetry monitor | `list(string)` | `[]` | no | +| [dropped\_d2c\_telemetry\_egress\_message](#input\_dropped\_d2c\_telemetry\_egress\_message) | Custom message for IoT Hub dropped d2c telemetry monitor | `string` | `""` | no | +| [dropped\_d2c\_telemetry\_egress\_rate\_threshold\_critical](#input\_dropped\_d2c\_telemetry\_egress\_rate\_threshold\_critical) | D2C Telemetry Dropped limit (critical threshold) | `number` | `90` | no | +| [dropped\_d2c\_telemetry\_egress\_rate\_threshold\_warning](#input\_dropped\_d2c\_telemetry\_egress\_rate\_threshold\_warning) | D2C Telemetry Dropped limit (warning threshold) | `number` | `50` | no | +| [dropped\_d2c\_telemetry\_egress\_time\_aggregator](#input\_dropped\_d2c\_telemetry\_egress\_time\_aggregator) | Monitor aggregator for IoT Hub dropped d2c telemetry [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [dropped\_d2c\_telemetry\_egress\_timeframe](#input\_dropped\_d2c\_telemetry\_egress\_timeframe) | Monitor timeframe for IoT Hub dropped d2c telemetry [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [failed\_c2d\_methods\_rate\_enabled](#input\_failed\_c2d\_methods\_rate\_enabled) | Flag to enable IoT Hub failed c2d methods monitor | `string` | `"true"` | no | +| [failed\_c2d\_methods\_rate\_extra\_tags](#input\_failed\_c2d\_methods\_rate\_extra\_tags) | Extra tags for IoT Hub failed c2d methods monitor | `list(string)` | `[]` | no | +| [failed\_c2d\_methods\_rate\_message](#input\_failed\_c2d\_methods\_rate\_message) | Custom message for IoT Hub failed c2d method monitor | `string` | `""` | no | +| [failed\_c2d\_methods\_rate\_threshold\_critical](#input\_failed\_c2d\_methods\_rate\_threshold\_critical) | C2D Methods Failed rate limit (critical threshold) | `number` | `90` | no | +| [failed\_c2d\_methods\_rate\_threshold\_warning](#input\_failed\_c2d\_methods\_rate\_threshold\_warning) | C2D Methods Failed rate limit (warning threshold) | `number` | `50` | no | +| [failed\_c2d\_methods\_rate\_time\_aggregator](#input\_failed\_c2d\_methods\_rate\_time\_aggregator) | Monitor aggregator for IoT Hub failed c2d method [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [failed\_c2d\_methods\_rate\_timeframe](#input\_failed\_c2d\_methods\_rate\_timeframe) | Monitor timeframe for IoT Hub failed c2d method [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [failed\_c2d\_twin\_read\_rate\_enabled](#input\_failed\_c2d\_twin\_read\_rate\_enabled) | Flag to enable IoT Hub failed c2d twin read monitor | `string` | `"true"` | no | +| [failed\_c2d\_twin\_read\_rate\_extra\_tags](#input\_failed\_c2d\_twin\_read\_rate\_extra\_tags) | Extra tags for IoT Hub failed c2d twin read monitor | `list(string)` | `[]` | no | +| [failed\_c2d\_twin\_read\_rate\_message](#input\_failed\_c2d\_twin\_read\_rate\_message) | Custom message for IoT Hub failed c2d twin read monitor | `string` | `""` | no | +| [failed\_c2d\_twin\_read\_rate\_threshold\_critical](#input\_failed\_c2d\_twin\_read\_rate\_threshold\_critical) | C2D Twin Read Failed rate limit (critical threshold) | `number` | `90` | no | +| [failed\_c2d\_twin\_read\_rate\_threshold\_warning](#input\_failed\_c2d\_twin\_read\_rate\_threshold\_warning) | C2D Twin Read Failed rate limit (warning threshold) | `number` | `50` | no | +| [failed\_c2d\_twin\_read\_rate\_time\_aggregator](#input\_failed\_c2d\_twin\_read\_rate\_time\_aggregator) | Monitor aggregator for IoT Hub failed c2d twin read [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [failed\_c2d\_twin\_read\_rate\_timeframe](#input\_failed\_c2d\_twin\_read\_rate\_timeframe) | Monitor timeframe for IoT Hub failed c2d twin read [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [failed\_c2d\_twin\_update\_rate\_enabled](#input\_failed\_c2d\_twin\_update\_rate\_enabled) | Flag to enable IoT Hub failed c2d twin update monitor | `string` | `"true"` | no | +| [failed\_c2d\_twin\_update\_rate\_extra\_tags](#input\_failed\_c2d\_twin\_update\_rate\_extra\_tags) | Extra tags for IoT Hub failed c2d twin update monitor | `list(string)` | `[]` | no | +| [failed\_c2d\_twin\_update\_rate\_message](#input\_failed\_c2d\_twin\_update\_rate\_message) | Custom message for IoT Hub failed c2d twin update monitor | `string` | `""` | no | +| [failed\_c2d\_twin\_update\_rate\_threshold\_critical](#input\_failed\_c2d\_twin\_update\_rate\_threshold\_critical) | C2D Twin Update Failed rate limit (critical threshold) | `number` | `90` | no | +| [failed\_c2d\_twin\_update\_rate\_threshold\_warning](#input\_failed\_c2d\_twin\_update\_rate\_threshold\_warning) | C2D Twin Update Failed rate limit (warning threshold) | `number` | `50` | no | +| [failed\_c2d\_twin\_update\_rate\_time\_aggregator](#input\_failed\_c2d\_twin\_update\_rate\_time\_aggregator) | Monitor aggregator for IoT Hub failed c2d twin update [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [failed\_c2d\_twin\_update\_rate\_timeframe](#input\_failed\_c2d\_twin\_update\_rate\_timeframe) | Monitor timeframe for IoT Hub failed c2d twin update [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [failed\_d2c\_twin\_read\_rate\_enabled](#input\_failed\_d2c\_twin\_read\_rate\_enabled) | Flag to enable IoT Hub failed d2c twin read monitor | `string` | `"true"` | no | +| [failed\_d2c\_twin\_read\_rate\_extra\_tags](#input\_failed\_d2c\_twin\_read\_rate\_extra\_tags) | Extra tags for IoT Hub failed d2c twin read monitor | `list(string)` | `[]` | no | +| [failed\_d2c\_twin\_read\_rate\_message](#input\_failed\_d2c\_twin\_read\_rate\_message) | Custom message for IoT Hub failed d2c twin read monitor | `string` | `""` | no | +| [failed\_d2c\_twin\_read\_rate\_threshold\_critical](#input\_failed\_d2c\_twin\_read\_rate\_threshold\_critical) | D2C Twin Read Failed rate limit (critical threshold) | `number` | `90` | no | +| [failed\_d2c\_twin\_read\_rate\_threshold\_warning](#input\_failed\_d2c\_twin\_read\_rate\_threshold\_warning) | D2C Twin Read Failed rate limit (warning threshold) | `number` | `50` | no | +| [failed\_d2c\_twin\_read\_rate\_time\_aggregator](#input\_failed\_d2c\_twin\_read\_rate\_time\_aggregator) | Monitor aggregator for IoT Hub failed d2c twin read [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [failed\_d2c\_twin\_read\_rate\_timeframe](#input\_failed\_d2c\_twin\_read\_rate\_timeframe) | Monitor timeframe for IoT Hub failed d2c twin read [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [failed\_d2c\_twin\_update\_rate\_enabled](#input\_failed\_d2c\_twin\_update\_rate\_enabled) | Flag to enable IoT Hub failed d2c twin update monitor | `string` | `"true"` | no | +| [failed\_d2c\_twin\_update\_rate\_extra\_tags](#input\_failed\_d2c\_twin\_update\_rate\_extra\_tags) | Extra tags for IoT Hub failed d2c twin update monitor | `list(string)` | `[]` | no | +| [failed\_d2c\_twin\_update\_rate\_message](#input\_failed\_d2c\_twin\_update\_rate\_message) | Custom message for IoT Hub failed d2c twin update monitor | `string` | `""` | no | +| [failed\_d2c\_twin\_update\_rate\_threshold\_critical](#input\_failed\_d2c\_twin\_update\_rate\_threshold\_critical) | D2C Twin Update Failed rate limit (critical threshold) | `number` | `90` | no | +| [failed\_d2c\_twin\_update\_rate\_threshold\_warning](#input\_failed\_d2c\_twin\_update\_rate\_threshold\_warning) | D2C Twin Update Failed rate limit (warning threshold) | `number` | `50` | no | +| [failed\_d2c\_twin\_update\_rate\_time\_aggregator](#input\_failed\_d2c\_twin\_update\_rate\_time\_aggregator) | Monitor aggregator for IoT Hub failed d2c twin update [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [failed\_d2c\_twin\_update\_rate\_timeframe](#input\_failed\_d2c\_twin\_update\_rate\_timeframe) | Monitor timeframe for IoT Hub failed d2c twin update [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [failed\_jobs\_rate\_enabled](#input\_failed\_jobs\_rate\_enabled) | Flag to enable IoT Hub failed jobs monitor | `string` | `"true"` | no | +| [failed\_jobs\_rate\_extra\_tags](#input\_failed\_jobs\_rate\_extra\_tags) | Extra tags for IoT Hub failed jobs monitor | `list(string)` | `[]` | no | +| [failed\_jobs\_rate\_message](#input\_failed\_jobs\_rate\_message) | Custom message for IoT Hub failed jobs monitor | `string` | `""` | no | +| [failed\_jobs\_rate\_threshold\_critical](#input\_failed\_jobs\_rate\_threshold\_critical) | Jobs Failed rate limit (critical threshold) | `number` | `90` | no | +| [failed\_jobs\_rate\_threshold\_warning](#input\_failed\_jobs\_rate\_threshold\_warning) | Jobs Failed rate limit (warning threshold) | `number` | `50` | no | +| [failed\_jobs\_rate\_time\_aggregator](#input\_failed\_jobs\_rate\_time\_aggregator) | Monitor aggregator for IoT Hub failed jobs [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [failed\_jobs\_rate\_timeframe](#input\_failed\_jobs\_rate\_timeframe) | Monitor timeframe for IoT Hub failed jobs [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [failed\_listjobs\_rate\_enabled](#input\_failed\_listjobs\_rate\_enabled) | Flag to enable IoT Hub failed list jobs monitor | `string` | `"true"` | no | +| [failed\_listjobs\_rate\_extra\_tags](#input\_failed\_listjobs\_rate\_extra\_tags) | Extra tags for IoT Hub failed list jobs monitor | `list(string)` | `[]` | no | +| [failed\_listjobs\_rate\_message](#input\_failed\_listjobs\_rate\_message) | Custom message for IoT Hub failed list jobs monitor | `string` | `""` | no | +| [failed\_listjobs\_rate\_threshold\_critical](#input\_failed\_listjobs\_rate\_threshold\_critical) | ListJobs Failed rate limit (critical threshold) | `number` | `90` | no | +| [failed\_listjobs\_rate\_threshold\_warning](#input\_failed\_listjobs\_rate\_threshold\_warning) | ListJobs Failed rate limit (warning threshold) | `number` | `50` | no | +| [failed\_listjobs\_rate\_time\_aggregator](#input\_failed\_listjobs\_rate\_time\_aggregator) | Monitor aggregator for IoT Hub failed list jobs [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [failed\_listjobs\_rate\_timeframe](#input\_failed\_listjobs\_rate\_timeframe) | Monitor timeframe for IoT Hub failed list jobs [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [failed\_queryjobs\_rate\_enabled](#input\_failed\_queryjobs\_rate\_enabled) | Flag to enable IoT Hub failed query jobs monitor | `string` | `"true"` | no | +| [failed\_queryjobs\_rate\_extra\_tags](#input\_failed\_queryjobs\_rate\_extra\_tags) | Extra tags for IoT Hub failed query jobs monitor | `list(string)` | `[]` | no | +| [failed\_queryjobs\_rate\_message](#input\_failed\_queryjobs\_rate\_message) | Custom message for IoT Hub failed query jobs monitor | `string` | `""` | no | +| [failed\_queryjobs\_rate\_threshold\_critical](#input\_failed\_queryjobs\_rate\_threshold\_critical) | QueryJobs Failed rate limit (critical threshold) | `number` | `90` | no | +| [failed\_queryjobs\_rate\_threshold\_warning](#input\_failed\_queryjobs\_rate\_threshold\_warning) | QueryJobs Failed rate limit (warning threshold) | `number` | `50` | no | +| [failed\_queryjobs\_rate\_time\_aggregator](#input\_failed\_queryjobs\_rate\_time\_aggregator) | Monitor aggregator for IoT Hub failed query jobs [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [failed\_queryjobs\_rate\_timeframe](#input\_failed\_queryjobs\_rate\_timeframe) | Monitor timeframe for IoT Hub failed query jobs [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [invalid\_d2c\_telemetry\_egress\_enabled](#input\_invalid\_d2c\_telemetry\_egress\_enabled) | Flag to enable IoT Hub invalid d2c telemetry monitor | `string` | `"true"` | no | +| [invalid\_d2c\_telemetry\_egress\_extra\_tags](#input\_invalid\_d2c\_telemetry\_egress\_extra\_tags) | Extra tags for IoT Hub invalid d2c telemetry monitor | `list(string)` | `[]` | no | +| [invalid\_d2c\_telemetry\_egress\_message](#input\_invalid\_d2c\_telemetry\_egress\_message) | Custom message for IoT Hub invalid d2c telemetry monitor | `string` | `""` | no | +| [invalid\_d2c\_telemetry\_egress\_rate\_threshold\_critical](#input\_invalid\_d2c\_telemetry\_egress\_rate\_threshold\_critical) | D2C Telemetry Invalid limit (critical threshold) | `number` | `90` | no | +| [invalid\_d2c\_telemetry\_egress\_rate\_threshold\_warning](#input\_invalid\_d2c\_telemetry\_egress\_rate\_threshold\_warning) | D2C Telemetry Invalid limit (warning threshold) | `number` | `50` | no | +| [invalid\_d2c\_telemetry\_egress\_time\_aggregator](#input\_invalid\_d2c\_telemetry\_egress\_time\_aggregator) | Monitor aggregator for IoT Hub invalid d2c telemetry [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [invalid\_d2c\_telemetry\_egress\_timeframe](#input\_invalid\_d2c\_telemetry\_egress\_timeframe) | Monitor timeframe for IoT Hub invalid d2c telemetry [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [orphaned\_d2c\_telemetry\_egress\_enabled](#input\_orphaned\_d2c\_telemetry\_egress\_enabled) | Flag to enable IoT Hub orphaned d2c telemetry monitor | `string` | `"true"` | no | +| [orphaned\_d2c\_telemetry\_egress\_extra\_tags](#input\_orphaned\_d2c\_telemetry\_egress\_extra\_tags) | Extra tags for IoT Hub orphaned d2c telemetry monitor | `list(string)` | `[]` | no | +| [orphaned\_d2c\_telemetry\_egress\_message](#input\_orphaned\_d2c\_telemetry\_egress\_message) | Custom message for IoT Hub orphaned d2c telemetry monitor | `string` | `""` | no | +| [orphaned\_d2c\_telemetry\_egress\_rate\_threshold\_critical](#input\_orphaned\_d2c\_telemetry\_egress\_rate\_threshold\_critical) | D2C Telemetry Orphaned limit (critical threshold) | `number` | `90` | no | +| [orphaned\_d2c\_telemetry\_egress\_rate\_threshold\_warning](#input\_orphaned\_d2c\_telemetry\_egress\_rate\_threshold\_warning) | D2C Telemetry Orphaned limit (warning threshold) | `number` | `50` | no | +| [orphaned\_d2c\_telemetry\_egress\_time\_aggregator](#input\_orphaned\_d2c\_telemetry\_egress\_time\_aggregator) | Monitor aggregator for IoT Hub orphaned d2c telemetry [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [orphaned\_d2c\_telemetry\_egress\_timeframe](#input\_orphaned\_d2c\_telemetry\_egress\_timeframe) | Monitor timeframe for IoT Hub orphaned d2c telemetry [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable IoT Hub status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for IoT Hub status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for IoT Hub status monitor | `string` | `""` | no | +| [status\_no\_data\_timeframe](#input\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for IoT Hub status [available values: min, max, sum or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for IoT Hub status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [too\_many\_d2c\_telemetry\_ingress\_nosent\_enabled](#input\_too\_many\_d2c\_telemetry\_ingress\_nosent\_enabled) | Flag to enable IoT Hub unsent d2c telemetry monitor | `string` | `"true"` | no | +| [too\_many\_d2c\_telemetry\_ingress\_nosent\_extra\_tags](#input\_too\_many\_d2c\_telemetry\_ingress\_nosent\_extra\_tags) | Extra tags for IoT Hub unsent d2c telemetry monitor | `list(string)` | `[]` | no | +| [too\_many\_d2c\_telemetry\_ingress\_nosent\_message](#input\_too\_many\_d2c\_telemetry\_ingress\_nosent\_message) | Custom message for IoT Hub unsent d2c telemetry monitor | `string` | `""` | no | +| [too\_many\_d2c\_telemetry\_ingress\_nosent\_rate\_threshold\_critical](#input\_too\_many\_d2c\_telemetry\_ingress\_nosent\_rate\_threshold\_critical) | D2C Telemetry ingress not sent limit (critical threshold) | `number` | `20` | no | +| [too\_many\_d2c\_telemetry\_ingress\_nosent\_rate\_threshold\_warning](#input\_too\_many\_d2c\_telemetry\_ingress\_nosent\_rate\_threshold\_warning) | D2C Telemetry ingress not sent limit (warning threshold) | `number` | `10` | no | +| [too\_many\_d2c\_telemetry\_ingress\_nosent\_timeframe](#input\_too\_many\_d2c\_telemetry\_ingress\_nosent\_timeframe) | Monitor timeframe for IoT Hub unsent d2c telemetry [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [total\_devices\_enabled](#input\_total\_devices\_enabled) | Flag to enable IoT Hub total devices monitor | `string` | `"true"` | no | +| [total\_devices\_extra\_tags](#input\_total\_devices\_extra\_tags) | Extra tags for IoT Hub total devices monitor | `list(string)` | `[]` | no | +| [total\_devices\_message](#input\_total\_devices\_message) | Custom message for IoT Hub total devices monitor | `string` | `""` | no | +| [total\_devices\_time\_aggregator](#input\_total\_devices\_time\_aggregator) | Monitor aggregator for IoT Hub total devices [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [total\_devices\_timeframe](#input\_total\_devices\_timeframe) | Monitor timeframe for IoT Hub total devices [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [status\_id](#output\_status\_id) | id for monitor status | +| [too\_many\_c2d\_methods\_failed\_id](#output\_too\_many\_c2d\_methods\_failed\_id) | id for monitor too\_many\_c2d\_methods\_failed | +| [too\_many\_c2d\_twin\_read\_failed\_id](#output\_too\_many\_c2d\_twin\_read\_failed\_id) | id for monitor too\_many\_c2d\_twin\_read\_failed | +| [too\_many\_c2d\_twin\_update\_failed\_id](#output\_too\_many\_c2d\_twin\_update\_failed\_id) | id for monitor too\_many\_c2d\_twin\_update\_failed | +| [too\_many\_d2c\_telemetry\_egress\_dropped\_id](#output\_too\_many\_d2c\_telemetry\_egress\_dropped\_id) | id for monitor too\_many\_d2c\_telemetry\_egress\_dropped | +| [too\_many\_d2c\_telemetry\_egress\_invalid\_id](#output\_too\_many\_d2c\_telemetry\_egress\_invalid\_id) | id for monitor too\_many\_d2c\_telemetry\_egress\_invalid | +| [too\_many\_d2c\_telemetry\_egress\_orphaned\_id](#output\_too\_many\_d2c\_telemetry\_egress\_orphaned\_id) | id for monitor too\_many\_d2c\_telemetry\_egress\_orphaned | +| [too\_many\_d2c\_telemetry\_ingress\_nosent\_id](#output\_too\_many\_d2c\_telemetry\_ingress\_nosent\_id) | id for monitor too\_many\_d2c\_telemetry\_ingress\_nosent | +| [too\_many\_d2c\_twin\_read\_failed\_id](#output\_too\_many\_d2c\_twin\_read\_failed\_id) | id for monitor too\_many\_d2c\_twin\_read\_failed | +| [too\_many\_d2c\_twin\_update\_failed\_id](#output\_too\_many\_d2c\_twin\_update\_failed\_id) | id for monitor too\_many\_d2c\_twin\_update\_failed | +| [too\_many\_jobs\_failed\_id](#output\_too\_many\_jobs\_failed\_id) | id for monitor too\_many\_jobs\_failed | +| [too\_many\_list\_jobs\_failed\_id](#output\_too\_many\_list\_jobs\_failed\_id) | id for monitor too\_many\_list\_jobs\_failed | +| [too\_many\_query\_jobs\_failed\_id](#output\_too\_many\_query\_jobs\_failed\_id) | id for monitor too\_many\_query\_jobs\_failed | +| [total\_devices\_id](#output\_total\_devices\_id) | id for monitor total\_devices | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure_iot_hub](https://docs.datadoghq.com/integrations/azure_iot_hub) + +Azure IOT Hubs metrics documentation: [https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-monitor-resource-health](https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-monitor-resource-health) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/iothubs/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/iothubs/inputs.tf new file mode 100755 index 0000000..0a5e90e --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/iothubs/inputs.tf @@ -0,0 +1,587 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# IOT Hub specific variables + +variable "status_enabled" { + description = "Flag to enable IoT Hub status monitor" + type = string + default = "true" +} + +variable "status_extra_tags" { + description = "Extra tags for IoT Hub status monitor" + type = list(string) + default = [] +} + +variable "status_message" { + description = "Custom message for IoT Hub status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for IoT Hub status [available values: min, max, sum or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for IoT Hub status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "total_devices_enabled" { + description = "Flag to enable IoT Hub total devices monitor" + type = string + default = "true" +} + +variable "total_devices_extra_tags" { + description = "Extra tags for IoT Hub total devices monitor" + type = list(string) + default = [] +} + +variable "total_devices_message" { + description = "Custom message for IoT Hub total devices monitor" + type = string + default = "" +} + +variable "total_devices_time_aggregator" { + description = "Monitor aggregator for IoT Hub total devices [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "total_devices_timeframe" { + description = "Monitor timeframe for IoT Hub total devices [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "too_many_d2c_telemetry_ingress_nosent_enabled" { + description = "Flag to enable IoT Hub unsent d2c telemetry monitor" + type = string + default = "true" +} + +variable "too_many_d2c_telemetry_ingress_nosent_extra_tags" { + description = "Extra tags for IoT Hub unsent d2c telemetry monitor" + type = list(string) + default = [] +} + +variable "too_many_d2c_telemetry_ingress_nosent_message" { + description = "Custom message for IoT Hub unsent d2c telemetry monitor" + type = string + default = "" +} + +variable "too_many_d2c_telemetry_ingress_nosent_timeframe" { + description = "Monitor timeframe for IoT Hub unsent d2c telemetry [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_jobs_rate_enabled" { + description = "Flag to enable IoT Hub failed jobs monitor" + type = string + default = "true" +} + +variable "failed_jobs_rate_extra_tags" { + description = "Extra tags for IoT Hub failed jobs monitor" + type = list(string) + default = [] +} + +variable "failed_jobs_rate_message" { + description = "Custom message for IoT Hub failed jobs monitor" + type = string + default = "" +} + +variable "failed_jobs_rate_time_aggregator" { + description = "Monitor aggregator for IoT Hub failed jobs [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "failed_jobs_rate_timeframe" { + description = "Monitor timeframe for IoT Hub failed jobs [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_jobs_rate_threshold_warning" { + description = "Jobs Failed rate limit (warning threshold)" + default = 50 +} + +variable "failed_jobs_rate_threshold_critical" { + description = "Jobs Failed rate limit (critical threshold)" + default = 90 +} + +variable "failed_listjobs_rate_enabled" { + description = "Flag to enable IoT Hub failed list jobs monitor" + type = string + default = "true" +} + +variable "failed_listjobs_rate_extra_tags" { + description = "Extra tags for IoT Hub failed list jobs monitor" + type = list(string) + default = [] +} + +variable "failed_listjobs_rate_message" { + description = "Custom message for IoT Hub failed list jobs monitor" + type = string + default = "" +} + +variable "failed_listjobs_rate_time_aggregator" { + description = "Monitor aggregator for IoT Hub failed list jobs [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "failed_listjobs_rate_timeframe" { + description = "Monitor timeframe for IoT Hub failed list jobs [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_listjobs_rate_threshold_warning" { + description = "ListJobs Failed rate limit (warning threshold)" + default = 50 +} + +variable "failed_listjobs_rate_threshold_critical" { + description = "ListJobs Failed rate limit (critical threshold)" + default = 90 +} + +variable "failed_queryjobs_rate_enabled" { + description = "Flag to enable IoT Hub failed query jobs monitor" + type = string + default = "true" +} + +variable "failed_queryjobs_rate_extra_tags" { + description = "Extra tags for IoT Hub failed query jobs monitor" + type = list(string) + default = [] +} + +variable "failed_queryjobs_rate_message" { + description = "Custom message for IoT Hub failed query jobs monitor" + type = string + default = "" +} + +variable "failed_queryjobs_rate_time_aggregator" { + description = "Monitor aggregator for IoT Hub failed query jobs [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "failed_queryjobs_rate_timeframe" { + description = "Monitor timeframe for IoT Hub failed query jobs [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_queryjobs_rate_threshold_warning" { + description = "QueryJobs Failed rate limit (warning threshold)" + default = 50 +} + +variable "failed_queryjobs_rate_threshold_critical" { + description = "QueryJobs Failed rate limit (critical threshold)" + default = 90 +} + +variable "failed_c2d_methods_rate_enabled" { + description = "Flag to enable IoT Hub failed c2d methods monitor" + type = string + default = "true" +} + +variable "failed_c2d_methods_rate_extra_tags" { + description = "Extra tags for IoT Hub failed c2d methods monitor" + type = list(string) + default = [] +} + +variable "failed_c2d_methods_rate_message" { + description = "Custom message for IoT Hub failed c2d method monitor" + type = string + default = "" +} + +variable "failed_c2d_methods_rate_time_aggregator" { + description = "Monitor aggregator for IoT Hub failed c2d method [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "failed_c2d_methods_rate_timeframe" { + description = "Monitor timeframe for IoT Hub failed c2d method [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_c2d_methods_rate_threshold_warning" { + description = "C2D Methods Failed rate limit (warning threshold)" + default = 50 +} + +variable "failed_c2d_methods_rate_threshold_critical" { + description = "C2D Methods Failed rate limit (critical threshold)" + default = 90 +} + +variable "failed_c2d_twin_read_rate_enabled" { + description = "Flag to enable IoT Hub failed c2d twin read monitor" + type = string + default = "true" +} + +variable "failed_c2d_twin_read_rate_extra_tags" { + description = "Extra tags for IoT Hub failed c2d twin read monitor" + type = list(string) + default = [] +} + +variable "failed_c2d_twin_read_rate_message" { + description = "Custom message for IoT Hub failed c2d twin read monitor" + type = string + default = "" +} + +variable "failed_c2d_twin_read_rate_time_aggregator" { + description = "Monitor aggregator for IoT Hub failed c2d twin read [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "failed_c2d_twin_read_rate_timeframe" { + description = "Monitor timeframe for IoT Hub failed c2d twin read [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_c2d_twin_read_rate_threshold_warning" { + description = "C2D Twin Read Failed rate limit (warning threshold)" + default = 50 +} + +variable "failed_c2d_twin_read_rate_threshold_critical" { + description = "C2D Twin Read Failed rate limit (critical threshold)" + default = 90 +} + +variable "failed_c2d_twin_update_rate_enabled" { + description = "Flag to enable IoT Hub failed c2d twin update monitor" + type = string + default = "true" +} + +variable "failed_c2d_twin_update_rate_extra_tags" { + description = "Extra tags for IoT Hub failed c2d twin update monitor" + type = list(string) + default = [] +} + +variable "failed_c2d_twin_update_rate_message" { + description = "Custom message for IoT Hub failed c2d twin update monitor" + type = string + default = "" +} + +variable "failed_c2d_twin_update_rate_time_aggregator" { + description = "Monitor aggregator for IoT Hub failed c2d twin update [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "failed_c2d_twin_update_rate_timeframe" { + description = "Monitor timeframe for IoT Hub failed c2d twin update [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_c2d_twin_update_rate_threshold_warning" { + description = "C2D Twin Update Failed rate limit (warning threshold)" + default = 50 +} + +variable "failed_c2d_twin_update_rate_threshold_critical" { + description = "C2D Twin Update Failed rate limit (critical threshold)" + default = 90 +} + +variable "failed_d2c_twin_read_rate_enabled" { + description = "Flag to enable IoT Hub failed d2c twin read monitor" + type = string + default = "true" +} + +variable "failed_d2c_twin_read_rate_extra_tags" { + description = "Extra tags for IoT Hub failed d2c twin read monitor" + type = list(string) + default = [] +} + +variable "failed_d2c_twin_read_rate_message" { + description = "Custom message for IoT Hub failed d2c twin read monitor" + type = string + default = "" +} + +variable "failed_d2c_twin_read_rate_time_aggregator" { + description = "Monitor aggregator for IoT Hub failed d2c twin read [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "failed_d2c_twin_read_rate_timeframe" { + description = "Monitor timeframe for IoT Hub failed d2c twin read [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_d2c_twin_read_rate_threshold_warning" { + description = "D2C Twin Read Failed rate limit (warning threshold)" + default = 50 +} + +variable "failed_d2c_twin_read_rate_threshold_critical" { + description = "D2C Twin Read Failed rate limit (critical threshold)" + default = 90 +} + +variable "failed_d2c_twin_update_rate_enabled" { + description = "Flag to enable IoT Hub failed d2c twin update monitor" + type = string + default = "true" +} + +variable "failed_d2c_twin_update_rate_extra_tags" { + description = "Extra tags for IoT Hub failed d2c twin update monitor" + type = list(string) + default = [] +} + +variable "failed_d2c_twin_update_rate_message" { + description = "Custom message for IoT Hub failed d2c twin update monitor" + type = string + default = "" +} + +variable "failed_d2c_twin_update_rate_time_aggregator" { + description = "Monitor aggregator for IoT Hub failed d2c twin update [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "failed_d2c_twin_update_rate_timeframe" { + description = "Monitor timeframe for IoT Hub failed d2c twin update [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_d2c_twin_update_rate_threshold_warning" { + description = "D2C Twin Update Failed rate limit (warning threshold)" + default = 50 +} + +variable "failed_d2c_twin_update_rate_threshold_critical" { + description = "D2C Twin Update Failed rate limit (critical threshold)" + default = 90 +} + +variable "dropped_d2c_telemetry_egress_enabled" { + description = "Flag to enable IoT Hub dropped d2c telemetry monitor" + type = string + default = "true" +} + +variable "dropped_d2c_telemetry_egress_extra_tags" { + description = "Extra tags for IoT Hub dropped d2c telemetry monitor" + type = list(string) + default = [] +} + +variable "dropped_d2c_telemetry_egress_message" { + description = "Custom message for IoT Hub dropped d2c telemetry monitor" + type = string + default = "" +} + +variable "dropped_d2c_telemetry_egress_time_aggregator" { + description = "Monitor aggregator for IoT Hub dropped d2c telemetry [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "dropped_d2c_telemetry_egress_timeframe" { + description = "Monitor timeframe for IoT Hub dropped d2c telemetry [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "dropped_d2c_telemetry_egress_rate_threshold_warning" { + description = "D2C Telemetry Dropped limit (warning threshold)" + default = 50 +} + +variable "dropped_d2c_telemetry_egress_rate_threshold_critical" { + description = "D2C Telemetry Dropped limit (critical threshold)" + default = 90 +} + +variable "orphaned_d2c_telemetry_egress_enabled" { + description = "Flag to enable IoT Hub orphaned d2c telemetry monitor" + type = string + default = "true" +} + +variable "orphaned_d2c_telemetry_egress_extra_tags" { + description = "Extra tags for IoT Hub orphaned d2c telemetry monitor" + type = list(string) + default = [] +} + +variable "orphaned_d2c_telemetry_egress_message" { + description = "Custom message for IoT Hub orphaned d2c telemetry monitor" + type = string + default = "" +} + +variable "orphaned_d2c_telemetry_egress_time_aggregator" { + description = "Monitor aggregator for IoT Hub orphaned d2c telemetry [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "orphaned_d2c_telemetry_egress_timeframe" { + description = "Monitor timeframe for IoT Hub orphaned d2c telemetry [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "orphaned_d2c_telemetry_egress_rate_threshold_warning" { + description = "D2C Telemetry Orphaned limit (warning threshold)" + default = 50 +} + +variable "orphaned_d2c_telemetry_egress_rate_threshold_critical" { + description = "D2C Telemetry Orphaned limit (critical threshold)" + default = 90 +} + +variable "invalid_d2c_telemetry_egress_enabled" { + description = "Flag to enable IoT Hub invalid d2c telemetry monitor" + type = string + default = "true" +} + +variable "invalid_d2c_telemetry_egress_extra_tags" { + description = "Extra tags for IoT Hub invalid d2c telemetry monitor" + type = list(string) + default = [] +} + +variable "invalid_d2c_telemetry_egress_message" { + description = "Custom message for IoT Hub invalid d2c telemetry monitor" + type = string + default = "" +} + +variable "invalid_d2c_telemetry_egress_time_aggregator" { + description = "Monitor aggregator for IoT Hub invalid d2c telemetry [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "invalid_d2c_telemetry_egress_timeframe" { + description = "Monitor timeframe for IoT Hub invalid d2c telemetry [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "invalid_d2c_telemetry_egress_rate_threshold_warning" { + description = "D2C Telemetry Invalid limit (warning threshold)" + default = 50 +} + +variable "invalid_d2c_telemetry_egress_rate_threshold_critical" { + description = "D2C Telemetry Invalid limit (critical threshold)" + default = 90 +} + +variable "too_many_d2c_telemetry_ingress_nosent_rate_threshold_critical" { + description = "D2C Telemetry ingress not sent limit (critical threshold)" + default = 20 +} + +variable "too_many_d2c_telemetry_ingress_nosent_rate_threshold_warning" { + description = "D2C Telemetry ingress not sent limit (warning threshold)" + default = 10 +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/iothubs/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/iothubs/modules.tf new file mode 100755 index 0000000..887245d --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/iothubs/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_iothubs" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/iothubs/monitors-iothubs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/iothubs/monitors-iothubs.tf new file mode 100755 index 0000000..a104616 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/iothubs/monitors-iothubs.tf @@ -0,0 +1,451 @@ +resource "datadog_monitor" "too_many_jobs_failed" { + count = var.failed_jobs_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub Too many jobs failed {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.failed_jobs_rate_message, var.message) + type = "query alert" + + query = < ${var.failed_jobs_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.failed_jobs_rate_threshold_warning + critical = var.failed_jobs_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.failed_jobs_rate_extra_tags) +} + +resource "datadog_monitor" "too_many_list_jobs_failed" { + count = var.failed_listjobs_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub Too many list_jobs failure {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.failed_listjobs_rate_message, var.message) + type = "query alert" + + query = < ${var.failed_listjobs_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.failed_listjobs_rate_threshold_warning + critical = var.failed_listjobs_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.failed_listjobs_rate_extra_tags) +} + +resource "datadog_monitor" "too_many_query_jobs_failed" { + count = var.failed_queryjobs_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub Too many query_jobs failed {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.failed_queryjobs_rate_message, var.message) + type = "query alert" + + query = < ${var.failed_queryjobs_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.failed_queryjobs_rate_threshold_warning + critical = var.failed_queryjobs_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.failed_queryjobs_rate_extra_tags) +} + +resource "datadog_monitor" "status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub is down" + message = coalesce(var.status_message, var.message) + type = "query alert" + + query = < ${var.failed_c2d_methods_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.failed_c2d_methods_rate_threshold_warning + critical = var.failed_c2d_methods_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.failed_c2d_methods_rate_extra_tags) +} + +resource "datadog_monitor" "too_many_c2d_twin_read_failed" { + count = var.failed_c2d_twin_read_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub Too many c2d twin read failure {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.failed_c2d_twin_read_rate_message, var.message) + type = "query alert" + + query = < ${var.failed_c2d_twin_read_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.failed_c2d_twin_read_rate_threshold_warning + critical = var.failed_c2d_twin_read_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.failed_c2d_twin_read_rate_extra_tags) +} + +resource "datadog_monitor" "too_many_c2d_twin_update_failed" { + count = var.failed_c2d_twin_update_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub Too many c2d twin update failure {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.failed_c2d_twin_update_rate_message, var.message) + type = "query alert" + + query = < ${var.failed_c2d_twin_update_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.failed_c2d_twin_update_rate_threshold_warning + critical = var.failed_c2d_twin_update_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.failed_c2d_twin_update_rate_extra_tags) +} + +resource "datadog_monitor" "too_many_d2c_twin_read_failed" { + count = var.failed_d2c_twin_read_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub Too many d2c twin read failure {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.failed_d2c_twin_read_rate_message, var.message) + type = "query alert" + + query = < ${var.failed_d2c_twin_read_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.failed_d2c_twin_read_rate_threshold_warning + critical = var.failed_d2c_twin_read_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.failed_d2c_twin_read_rate_extra_tags) +} + +resource "datadog_monitor" "too_many_d2c_twin_update_failed" { + count = var.failed_d2c_twin_update_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub Too many d2c twin update failure {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.failed_d2c_twin_update_rate_message, var.message) + type = "query alert" + + query = < ${var.failed_d2c_twin_update_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.failed_d2c_twin_update_rate_threshold_warning + critical = var.failed_d2c_twin_update_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.failed_d2c_twin_update_rate_extra_tags) +} + +resource "datadog_monitor" "too_many_d2c_telemetry_egress_dropped" { + count = var.dropped_d2c_telemetry_egress_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub Too many d2c telemetry egress dropped {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.dropped_d2c_telemetry_egress_message, var.message) + type = "query alert" + + query = < ${var.dropped_d2c_telemetry_egress_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.dropped_d2c_telemetry_egress_rate_threshold_warning + critical = var.dropped_d2c_telemetry_egress_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.dropped_d2c_telemetry_egress_extra_tags) +} + +resource "datadog_monitor" "too_many_d2c_telemetry_egress_orphaned" { + count = var.orphaned_d2c_telemetry_egress_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub Too many d2c telemetry egress orphaned {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.orphaned_d2c_telemetry_egress_message, var.message) + type = "query alert" + + query = < ${var.orphaned_d2c_telemetry_egress_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.orphaned_d2c_telemetry_egress_rate_threshold_warning + critical = var.orphaned_d2c_telemetry_egress_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.orphaned_d2c_telemetry_egress_extra_tags) +} + +resource "datadog_monitor" "too_many_d2c_telemetry_egress_invalid" { + count = var.invalid_d2c_telemetry_egress_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub Too many d2c telemetry egress invalid {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.invalid_d2c_telemetry_egress_message, var.message) + type = "query alert" + + query = < ${var.invalid_d2c_telemetry_egress_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.invalid_d2c_telemetry_egress_rate_threshold_warning + critical = var.invalid_d2c_telemetry_egress_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.invalid_d2c_telemetry_egress_extra_tags) +} + +resource "datadog_monitor" "too_many_d2c_telemetry_ingress_nosent" { + count = var.too_many_d2c_telemetry_ingress_nosent_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub Too many d2c telemetry ingress not sent {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.too_many_d2c_telemetry_ingress_nosent_message, var.message) + type = "query alert" + + #For this monitor, the avg is needed to smooth the -1 and +1 that we meet regularly. With just a tiny diff like -1 / + 1, if we put 0.3 it should not ring anymore. But there is a bigger difference (exemple 20) The average will be strongly raised and an alert will be triggered. + query = < ${var.too_many_d2c_telemetry_ingress_nosent_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.too_many_d2c_telemetry_ingress_nosent_rate_threshold_warning + critical = var.too_many_d2c_telemetry_ingress_nosent_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.too_many_d2c_telemetry_ingress_nosent_extra_tags) +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/iothubs/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/iothubs/outputs.tf new file mode 100755 index 0000000..31dd33d --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/iothubs/outputs.tf @@ -0,0 +1,70 @@ +output "status_id" { + description = "id for monitor status" + value = datadog_monitor.status.*.id +} + +output "too_many_c2d_methods_failed_id" { + description = "id for monitor too_many_c2d_methods_failed" + value = datadog_monitor.too_many_c2d_methods_failed.*.id +} + +output "too_many_c2d_twin_read_failed_id" { + description = "id for monitor too_many_c2d_twin_read_failed" + value = datadog_monitor.too_many_c2d_twin_read_failed.*.id +} + +output "too_many_c2d_twin_update_failed_id" { + description = "id for monitor too_many_c2d_twin_update_failed" + value = datadog_monitor.too_many_c2d_twin_update_failed.*.id +} + +output "too_many_d2c_telemetry_egress_dropped_id" { + description = "id for monitor too_many_d2c_telemetry_egress_dropped" + value = datadog_monitor.too_many_d2c_telemetry_egress_dropped.*.id +} + +output "too_many_d2c_telemetry_egress_invalid_id" { + description = "id for monitor too_many_d2c_telemetry_egress_invalid" + value = datadog_monitor.too_many_d2c_telemetry_egress_invalid.*.id +} + +output "too_many_d2c_telemetry_egress_orphaned_id" { + description = "id for monitor too_many_d2c_telemetry_egress_orphaned" + value = datadog_monitor.too_many_d2c_telemetry_egress_orphaned.*.id +} + +output "too_many_d2c_telemetry_ingress_nosent_id" { + description = "id for monitor too_many_d2c_telemetry_ingress_nosent" + value = datadog_monitor.too_many_d2c_telemetry_ingress_nosent.*.id +} + +output "too_many_d2c_twin_read_failed_id" { + description = "id for monitor too_many_d2c_twin_read_failed" + value = datadog_monitor.too_many_d2c_twin_read_failed.*.id +} + +output "too_many_d2c_twin_update_failed_id" { + description = "id for monitor too_many_d2c_twin_update_failed" + value = datadog_monitor.too_many_d2c_twin_update_failed.*.id +} + +output "too_many_jobs_failed_id" { + description = "id for monitor too_many_jobs_failed" + value = datadog_monitor.too_many_jobs_failed.*.id +} + +output "too_many_list_jobs_failed_id" { + description = "id for monitor too_many_list_jobs_failed" + value = datadog_monitor.too_many_list_jobs_failed.*.id +} + +output "too_many_query_jobs_failed_id" { + description = "id for monitor too_many_query_jobs_failed" + value = datadog_monitor.too_many_query_jobs_failed.*.id +} + +output "total_devices_id" { + description = "id for monitor total_devices" + value = datadog_monitor.total_devices.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/iothubs/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/iothubs/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/iothubs/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/keyvault/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/keyvault/README.md new file mode 100755 index 0000000..e74f597 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/keyvault/README.md @@ -0,0 +1,99 @@ +# CLOUD AZURE KEYVAULT DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-keyvault" { + source = "claranet/monitors/datadog//cloud/azure/keyvault" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Key Vault API latency is high +- Key Vault API result rate is low +- Key Vault is down + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | +| [filter-tags-activity](#module\_filter-tags-activity) | ../../../common/filter-tags | n/a | +| [filter-tags-statuscode](#module\_filter-tags-statuscode) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.keyvault_api_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.keyvault_api_result](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.keyvault_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [api\_latency\_enabled](#input\_api\_latency\_enabled) | Flag to enable Key Vault API latency monitor | `string` | `"true"` | no | +| [api\_latency\_extra\_tags](#input\_api\_latency\_extra\_tags) | Extra tags for Key Vault API latency monitor | `list(string)` | `[]` | no | +| [api\_latency\_message](#input\_api\_latency\_message) | Custom message for Key Vault API latency monitor | `string` | `""` | no | +| [api\_latency\_threshold\_critical](#input\_api\_latency\_threshold\_critical) | Critical threshold for Key Vault API latency rate | `number` | `100` | no | +| [api\_latency\_threshold\_warning](#input\_api\_latency\_threshold\_warning) | Warning threshold for Key Vault API latency rate | `number` | `80` | no | +| [api\_latency\_time\_aggregator](#input\_api\_latency\_time\_aggregator) | Monitor aggregator for Key Vault API latency [available values: min, max or avg] | `string` | `"min"` | no | +| [api\_latency\_timeframe](#input\_api\_latency\_timeframe) | Monitor timeframe for Key Vault API latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [api\_result\_enabled](#input\_api\_result\_enabled) | Flag to enable Key Vault API result monitor | `string` | `"true"` | no | +| [api\_result\_extra\_tags](#input\_api\_result\_extra\_tags) | Extra tags for Key Vault API result monitor | `list(string)` | `[]` | no | +| [api\_result\_message](#input\_api\_result\_message) | Custom message for Key Vault API result monitor | `string` | `""` | no | +| [api\_result\_threshold\_critical](#input\_api\_result\_threshold\_critical) | Critical threshold for Key Vault API result rate | `number` | `10` | no | +| [api\_result\_threshold\_warning](#input\_api\_result\_threshold\_warning) | Warning threshold for Key Vault API result rate | `number` | `30` | no | +| [api\_result\_time\_aggregator](#input\_api\_result\_time\_aggregator) | Monitor aggregator for Key Vault API result [available values: min, max or avg] | `string` | `"max"` | no | +| [api\_result\_timeframe](#input\_api\_result\_timeframe) | Monitor timeframe for Key Vault API result [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [keyvault\_status\_no\_data\_timeframe](#input\_keyvault\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable Key Vault status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for Key Vault status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for Key Vault status monitor | `string` | `""` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for Key Vault status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for Key Vault status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [keyvault\_api\_latency\_id](#output\_keyvault\_api\_latency\_id) | id for monitor keyvault\_api\_latency | +| [keyvault\_api\_result\_id](#output\_keyvault\_api\_result\_id) | id for monitor keyvault\_api\_result | +| [keyvault\_status\_id](#output\_keyvault\_status\_id) | id for monitor keyvault\_status | +## Related documentation + +DataDog documentation : [https://docs.datadoghq.com/integrations/azure/](https://docs.datadoghq.com/integrations/azure/) +You must search `keyvault`, there is no integration for now. + +Azure metrics documentation : [https://docs.microsoft.com/fr-fr/azure/monitoring-and-diagnostics/monitoring-supported-metrics#microsoftkeyvaultvaults](https://docs.microsoft.com/fr-fr/azure/monitoring-and-diagnostics/monitoring-supported-metrics#microsoftkeyvaultvaults) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/keyvault/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/keyvault/inputs.tf new file mode 100755 index 0000000..177752c --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/keyvault/inputs.tf @@ -0,0 +1,158 @@ +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "keyvault_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# Azure Key Vault specific variables +variable "status_enabled" { + description = "Flag to enable Key Vault status monitor" + type = string + default = "true" +} + +variable "status_message" { + description = "Custom message for Key Vault status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for Key Vault status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for Key Vault status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + default = "last_5m" +} + +variable "status_extra_tags" { + description = "Extra tags for Key Vault status monitor" + type = list(string) + default = [] +} + +variable "api_result_enabled" { + description = "Flag to enable Key Vault API result monitor" + type = string + default = "true" +} + +variable "api_result_message" { + description = "Custom message for Key Vault API result monitor" + type = string + default = "" +} + +variable "api_result_time_aggregator" { + description = "Monitor aggregator for Key Vault API result [available values: min, max or avg]" + type = string + default = "max" +} + +variable "api_result_timeframe" { + description = "Monitor timeframe for Key Vault API result [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + default = "last_5m" +} + +variable "api_result_threshold_critical" { + description = "Critical threshold for Key Vault API result rate" + default = 10 +} + +variable "api_result_threshold_warning" { + description = "Warning threshold for Key Vault API result rate" + default = 30 +} + +variable "api_result_extra_tags" { + description = "Extra tags for Key Vault API result monitor" + type = list(string) + default = [] +} + +variable "api_latency_enabled" { + description = "Flag to enable Key Vault API latency monitor" + type = string + default = "true" +} + +variable "api_latency_message" { + description = "Custom message for Key Vault API latency monitor" + type = string + default = "" +} + +variable "api_latency_time_aggregator" { + description = "Monitor aggregator for Key Vault API latency [available values: min, max or avg]" + type = string + default = "min" +} + +variable "api_latency_timeframe" { + description = "Monitor timeframe for Key Vault API latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + default = "last_5m" +} + +variable "api_latency_threshold_critical" { + description = "Critical threshold for Key Vault API latency rate" + default = 100 +} + +variable "api_latency_threshold_warning" { + description = "Warning threshold for Key Vault API latency rate" + default = 80 +} + +variable "api_latency_extra_tags" { + description = "Extra tags for Key Vault API latency monitor" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/keyvault/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/keyvault/modules.tf new file mode 100755 index 0000000..9fd2ab3 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/keyvault/modules.tf @@ -0,0 +1,32 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_keyvault" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + +module "filter-tags-statuscode" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_keyvault" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["statuscode:%s"] +} + +module "filter-tags-activity" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_keyvault" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags_excluded = ["activityname:secretlist"] +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/keyvault/monitors-keyvault.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/keyvault/monitors-keyvault.tf new file mode 100755 index 0000000..85fb14b --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/keyvault/monitors-keyvault.tf @@ -0,0 +1,89 @@ +resource "datadog_monitor" "keyvault_status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Key Vault is down" + message = coalesce(var.status_message, var.message) + type = "query alert" + + query = < ${var.api_latency_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.api_latency_threshold_critical + warning = var.api_latency_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:keyvault", "team:claranet", "created-by:terraform"], var.api_latency_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/keyvault/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/keyvault/outputs.tf new file mode 100755 index 0000000..8f67e0b --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/keyvault/outputs.tf @@ -0,0 +1,15 @@ +output "keyvault_api_latency_id" { + description = "id for monitor keyvault_api_latency" + value = datadog_monitor.keyvault_api_latency.*.id +} + +output "keyvault_api_result_id" { + description = "id for monitor keyvault_api_result" + value = datadog_monitor.keyvault_api_result.*.id +} + +output "keyvault_status_id" { + description = "id for monitor keyvault_status" + value = datadog_monitor.keyvault_status.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/keyvault/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/keyvault/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/keyvault/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/load-balancer/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/load-balancer/README.md new file mode 100755 index 0000000..d4c337e --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/load-balancer/README.md @@ -0,0 +1,74 @@ +# CLOUD AZURE LOAD-BALANCER DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-load-balancer" { + source = "claranet/monitors/datadog//cloud/azure/load-balancer" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Load Balancer is unreachable + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.loadbalancer_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [loadbalancer\_status\_no\_data\_timeframe](#input\_loadbalancer\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable Load Balancer status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for Load Balancer status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for Load Balancer status monitor | `string` | `""` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for Load Balancer status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for Load Balancer status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [loadbalancer\_status\_id](#output\_loadbalancer\_status\_id) | id for monitor loadbalancer\_status | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure/?tab=azurecliv20](https://docs.datadoghq.com/integrations/azure/?tab=azurecliv20) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/load-balancer/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/load-balancer/inputs.tf new file mode 100755 index 0000000..614411f --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/load-balancer/inputs.tf @@ -0,0 +1,80 @@ +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "loadbalancer_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# Azure Load Balancer specific variables +variable "status_enabled" { + description = "Flag to enable Load Balancer status monitor" + type = string + default = "true" +} + +variable "status_message" { + description = "Custom message for Load Balancer status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for Load Balancer status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for Load Balancer status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + default = "last_5m" +} + +variable "status_extra_tags" { + description = "Extra tags for Load Balancer status monitor" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/load-balancer/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/load-balancer/modules.tf new file mode 100755 index 0000000..d68393b --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/load-balancer/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_load-balancer" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/load-balancer/monitors-load-balancer.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/load-balancer/monitors-load-balancer.tf new file mode 100755 index 0000000..3ffdf53 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/load-balancer/monitors-load-balancer.tf @@ -0,0 +1,26 @@ +resource "datadog_monitor" "loadbalancer_status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Load Balancer is unreachable" + message = coalesce(var.status_message, var.message) + type = "query alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.mysql_cpu_usage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_free_storage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_io_consumption](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_memory_usage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_usage\_enabled](#input\_cpu\_usage\_enabled) | Flag to enable Mysql status monitor | `string` | `"true"` | no | +| [cpu\_usage\_extra\_tags](#input\_cpu\_usage\_extra\_tags) | Extra tags for Mysql status monitor | `list(string)` | `[]` | no | +| [cpu\_usage\_message](#input\_cpu\_usage\_message) | Custom message for Mysql CPU monitor | `string` | `""` | no | +| [cpu\_usage\_threshold\_critical](#input\_cpu\_usage\_threshold\_critical) | Mysql CPU usage in percent (critical threshold) | `string` | `"90"` | no | +| [cpu\_usage\_threshold\_warning](#input\_cpu\_usage\_threshold\_warning) | Mysql CPU usage in percent (warning threshold) | `string` | `"80"` | no | +| [cpu\_usage\_time\_aggregator](#input\_cpu\_usage\_time\_aggregator) | Monitor aggregator for Mysql CPU [available values: min, max or avg] | `string` | `"min"` | no | +| [cpu\_usage\_timeframe](#input\_cpu\_usage\_timeframe) | Monitor timeframe for Mysql CPU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [free\_storage\_enabled](#input\_free\_storage\_enabled) | Flag to enable Mysql status monitor | `string` | `"true"` | no | +| [free\_storage\_extra\_tags](#input\_free\_storage\_extra\_tags) | Extra tags for Mysql status monitor | `list(string)` | `[]` | no | +| [free\_storage\_message](#input\_free\_storage\_message) | Custom message for Mysql Free Storage monitor | `string` | `""` | no | +| [free\_storage\_threshold\_critical](#input\_free\_storage\_threshold\_critical) | Mysql Free Storage remaining in percent (critical threshold) | `string` | `"10"` | no | +| [free\_storage\_threshold\_warning](#input\_free\_storage\_threshold\_warning) | Mysql Free Storage remaining in percent (warning threshold) | `string` | `"20"` | no | +| [free\_storage\_time\_aggregator](#input\_free\_storage\_time\_aggregator) | Monitor aggregator for Mysql Free Storage [available values: min, max or avg] | `string` | `"min"` | no | +| [free\_storage\_timeframe](#input\_free\_storage\_timeframe) | Monitor timeframe for Mysql Free Storage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [io\_consumption\_enabled](#input\_io\_consumption\_enabled) | Flag to enable Mysql status monitor | `string` | `"true"` | no | +| [io\_consumption\_extra\_tags](#input\_io\_consumption\_extra\_tags) | Extra tags for Mysql status monitor | `list(string)` | `[]` | no | +| [io\_consumption\_message](#input\_io\_consumption\_message) | Custom message for Mysql IO consumption monitor | `string` | `""` | no | +| [io\_consumption\_threshold\_critical](#input\_io\_consumption\_threshold\_critical) | Mysql IO consumption in percent (critical threshold) | `string` | `"90"` | no | +| [io\_consumption\_threshold\_warning](#input\_io\_consumption\_threshold\_warning) | Mysql IO consumption in percent (warning threshold) | `string` | `"80"` | no | +| [io\_consumption\_time\_aggregator](#input\_io\_consumption\_time\_aggregator) | Monitor aggregator for Mysql IO consumption [available values: min, max or avg] | `string` | `"min"` | no | +| [io\_consumption\_timeframe](#input\_io\_consumption\_timeframe) | Monitor timeframe for Mysql IO consumption [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [memory\_usage\_enabled](#input\_memory\_usage\_enabled) | Flag to enable Mysql status monitor | `string` | `"true"` | no | +| [memory\_usage\_extra\_tags](#input\_memory\_usage\_extra\_tags) | Extra tags for Mysql status monitor | `list(string)` | `[]` | no | +| [memory\_usage\_message](#input\_memory\_usage\_message) | Custom message for Mysql memory monitor | `string` | `""` | no | +| [memory\_usage\_threshold\_critical](#input\_memory\_usage\_threshold\_critical) | Mysql memory usage in percent (critical threshold) | `string` | `"90"` | no | +| [memory\_usage\_threshold\_warning](#input\_memory\_usage\_threshold\_warning) | Mysql memory usage in percent (warning threshold) | `string` | `"80"` | no | +| [memory\_usage\_time\_aggregator](#input\_memory\_usage\_time\_aggregator) | Monitor aggregator for Mysql memory [available values: min, max or avg] | `string` | `"min"` | no | +| [memory\_usage\_timeframe](#input\_memory\_usage\_timeframe) | Monitor timeframe for Mysql memory [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [mysql\_cpu\_usage\_id](#output\_mysql\_cpu\_usage\_id) | id for monitor mysql\_cpu\_usage | +| [mysql\_free\_storage\_id](#output\_mysql\_free\_storage\_id) | id for monitor mysql\_free\_storage | +| [mysql\_io\_consumption\_id](#output\_mysql\_io\_consumption\_id) | id for monitor mysql\_io\_consumption | +| [mysql\_memory\_usage\_id](#output\_mysql\_memory\_usage\_id) | id for monitor mysql\_memory\_usage | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure/](https://docs.datadoghq.com/integrations/azure/) +You have to search `mysql` + +Azure Database for MySQL servers metrics documentation: [https://docs.microsoft.com/en-us/azure/mysql/concepts-monitoring](https://docs.microsoft.com/en-us/azure/mysql/concepts-monitoring) + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/mysql/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/mysql/inputs.tf new file mode 100755 index 0000000..681cc49 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/mysql/inputs.tf @@ -0,0 +1,203 @@ +# Global Terraform +variable "environment" { + description = "Architecture environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +# Azure Databases for MySQL Servers specific variables + +variable "cpu_usage_enabled" { + description = "Flag to enable Mysql status monitor" + type = string + default = "true" +} + +variable "cpu_usage_extra_tags" { + description = "Extra tags for Mysql status monitor" + type = list(string) + default = [] +} + +variable "cpu_usage_message" { + description = "Custom message for Mysql CPU monitor" + type = string + default = "" +} + +variable "cpu_usage_time_aggregator" { + description = "Monitor aggregator for Mysql CPU [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cpu_usage_timeframe" { + description = "Monitor timeframe for Mysql CPU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "cpu_usage_threshold_warning" { + description = "Mysql CPU usage in percent (warning threshold)" + default = "80" +} + +variable "cpu_usage_threshold_critical" { + description = "Mysql CPU usage in percent (critical threshold)" + default = "90" +} + +variable "free_storage_enabled" { + description = "Flag to enable Mysql status monitor" + type = string + default = "true" +} + +variable "free_storage_extra_tags" { + description = "Extra tags for Mysql status monitor" + type = list(string) + default = [] +} + +variable "free_storage_message" { + description = "Custom message for Mysql Free Storage monitor" + type = string + default = "" +} + +variable "free_storage_time_aggregator" { + description = "Monitor aggregator for Mysql Free Storage [available values: min, max or avg]" + type = string + default = "min" +} + +variable "free_storage_timeframe" { + description = "Monitor timeframe for Mysql Free Storage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "free_storage_threshold_warning" { + description = "Mysql Free Storage remaining in percent (warning threshold)" + default = "20" +} + +variable "free_storage_threshold_critical" { + description = "Mysql Free Storage remaining in percent (critical threshold)" + default = "10" +} + +variable "io_consumption_enabled" { + description = "Flag to enable Mysql status monitor" + type = string + default = "true" +} + +variable "io_consumption_extra_tags" { + description = "Extra tags for Mysql status monitor" + type = list(string) + default = [] +} + +variable "io_consumption_message" { + description = "Custom message for Mysql IO consumption monitor" + type = string + default = "" +} + +variable "io_consumption_time_aggregator" { + description = "Monitor aggregator for Mysql IO consumption [available values: min, max or avg]" + type = string + default = "min" +} + +variable "io_consumption_timeframe" { + description = "Monitor timeframe for Mysql IO consumption [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "io_consumption_threshold_warning" { + description = "Mysql IO consumption in percent (warning threshold)" + default = "80" +} + +variable "io_consumption_threshold_critical" { + description = "Mysql IO consumption in percent (critical threshold)" + default = "90" +} + +variable "memory_usage_enabled" { + description = "Flag to enable Mysql status monitor" + type = string + default = "true" +} + +variable "memory_usage_extra_tags" { + description = "Extra tags for Mysql status monitor" + type = list(string) + default = [] +} + +variable "memory_usage_message" { + description = "Custom message for Mysql memory monitor" + type = string + default = "" +} + +variable "memory_usage_time_aggregator" { + description = "Monitor aggregator for Mysql memory [available values: min, max or avg]" + type = string + default = "min" +} + +variable "memory_usage_timeframe" { + description = "Monitor timeframe for Mysql memory [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "memory_usage_threshold_warning" { + description = "Mysql memory usage in percent (warning threshold)" + default = "80" +} + +variable "memory_usage_threshold_critical" { + description = "Mysql memory usage in percent (critical threshold)" + default = "90" +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/mysql/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/mysql/modules.tf new file mode 100755 index 0000000..87489ca --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/mysql/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_mysql" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/mysql/monitors-mysql.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/mysql/monitors-mysql.tf new file mode 100755 index 0000000..6e24841 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/mysql/monitors-mysql.tf @@ -0,0 +1,120 @@ +resource "datadog_monitor" "mysql_cpu_usage" { + count = var.cpu_usage_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql Server CPU usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cpu_usage_message, var.message) + type = "query alert" + + query = < ${var.cpu_usage_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.cpu_usage_threshold_critical + warning = var.cpu_usage_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:mysql", "team:claranet", "created-by:terraform"], var.cpu_usage_extra_tags) +} + +resource "datadog_monitor" "mysql_free_storage" { + count = var.free_storage_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql Server storage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.free_storage_message, var.message) + type = "query alert" + + query = < ${var.io_consumption_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.io_consumption_threshold_critical + warning = var.io_consumption_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:mysql", "team:claranet", "created-by:terraform"], var.io_consumption_extra_tags) +} + +resource "datadog_monitor" "mysql_memory_usage" { + count = var.memory_usage_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql Server memory usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.memory_usage_message, var.message) + type = "query alert" + + query = < ${var.memory_usage_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.memory_usage_threshold_critical + warning = var.memory_usage_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:mysql", "team:claranet", "created-by:terraform"], var.memory_usage_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/mysql/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/mysql/outputs.tf new file mode 100755 index 0000000..ace5b8a --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/mysql/outputs.tf @@ -0,0 +1,20 @@ +output "mysql_cpu_usage_id" { + description = "id for monitor mysql_cpu_usage" + value = datadog_monitor.mysql_cpu_usage.*.id +} + +output "mysql_free_storage_id" { + description = "id for monitor mysql_free_storage" + value = datadog_monitor.mysql_free_storage.*.id +} + +output "mysql_io_consumption_id" { + description = "id for monitor mysql_io_consumption" + value = datadog_monitor.mysql_io_consumption.*.id +} + +output "mysql_memory_usage_id" { + description = "id for monitor mysql_memory_usage" + value = datadog_monitor.mysql_memory_usage.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/mysql/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/mysql/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/mysql/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/postgresql/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/postgresql/README.md new file mode 100755 index 0000000..4e1121c --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/postgresql/README.md @@ -0,0 +1,114 @@ +# CLOUD AZURE POSTGRESQL DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-postgresql" { + source = "claranet/monitors/datadog//cloud/azure/postgresql" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Postgresql Server CPU usage +- Postgresql Server has no connection +- Postgresql Server IO consumption +- Postgresql Server memory usage +- Postgresql Server storage + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.postgresql_cpu_usage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.postgresql_free_storage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.postgresql_io_consumption](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.postgresql_memory_usage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.postgresql_no_connection](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_usage\_enabled](#input\_cpu\_usage\_enabled) | Flag to enable PostgreSQL status monitor | `string` | `"true"` | no | +| [cpu\_usage\_extra\_tags](#input\_cpu\_usage\_extra\_tags) | Extra tags for PostgreSQL status monitor | `list(string)` | `[]` | no | +| [cpu\_usage\_message](#input\_cpu\_usage\_message) | Custom message for PostgreSQL CPU monitor | `string` | `""` | no | +| [cpu\_usage\_threshold\_critical](#input\_cpu\_usage\_threshold\_critical) | PostgreSQL CPU usage in percent (critical threshold) | `string` | `"90"` | no | +| [cpu\_usage\_threshold\_warning](#input\_cpu\_usage\_threshold\_warning) | PostgreSQL CPU usage in percent (warning threshold) | `string` | `"80"` | no | +| [cpu\_usage\_time\_aggregator](#input\_cpu\_usage\_time\_aggregator) | Monitor aggregator for PostgreSQL CPU [available values: min, max or avg] | `string` | `"min"` | no | +| [cpu\_usage\_timeframe](#input\_cpu\_usage\_timeframe) | Monitor timeframe for PostgreSQL CPU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [free\_storage\_enabled](#input\_free\_storage\_enabled) | Flag to enable PostgreSQL status monitor | `string` | `"true"` | no | +| [free\_storage\_extra\_tags](#input\_free\_storage\_extra\_tags) | Extra tags for PostgreSQL status monitor | `list(string)` | `[]` | no | +| [free\_storage\_message](#input\_free\_storage\_message) | Custom message for PostgreSQL Free Storage monitor | `string` | `""` | no | +| [free\_storage\_threshold\_critical](#input\_free\_storage\_threshold\_critical) | PostgreSQL Free Storage remaining in percent (critical threshold) | `string` | `"10"` | no | +| [free\_storage\_threshold\_warning](#input\_free\_storage\_threshold\_warning) | PostgreSQL Free Storage remaining in percent (warning threshold) | `string` | `"20"` | no | +| [free\_storage\_time\_aggregator](#input\_free\_storage\_time\_aggregator) | Monitor aggregator for PostgreSQL Free Storage [available values: min, max or avg] | `string` | `"min"` | no | +| [free\_storage\_timeframe](#input\_free\_storage\_timeframe) | Monitor timeframe for PostgreSQL Free Storage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [io\_consumption\_enabled](#input\_io\_consumption\_enabled) | Flag to enable PostgreSQL status monitor | `string` | `"true"` | no | +| [io\_consumption\_extra\_tags](#input\_io\_consumption\_extra\_tags) | Extra tags for PostgreSQL status monitor | `list(string)` | `[]` | no | +| [io\_consumption\_message](#input\_io\_consumption\_message) | Custom message for PostgreSQL IO consumption monitor | `string` | `""` | no | +| [io\_consumption\_threshold\_critical](#input\_io\_consumption\_threshold\_critical) | PostgreSQL IO consumption in percent (critical threshold) | `string` | `"90"` | no | +| [io\_consumption\_threshold\_warning](#input\_io\_consumption\_threshold\_warning) | PostgreSQL IO consumption in percent (warning threshold) | `string` | `"80"` | no | +| [io\_consumption\_time\_aggregator](#input\_io\_consumption\_time\_aggregator) | Monitor aggregator for PostgreSQL IO consumption [available values: min, max or avg] | `string` | `"min"` | no | +| [io\_consumption\_timeframe](#input\_io\_consumption\_timeframe) | Monitor timeframe for PostgreSQL IO consumption [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [memory\_usage\_enabled](#input\_memory\_usage\_enabled) | Flag to enable PostgreSQL status monitor | `string` | `"true"` | no | +| [memory\_usage\_extra\_tags](#input\_memory\_usage\_extra\_tags) | Extra tags for PostgreSQL status monitor | `list(string)` | `[]` | no | +| [memory\_usage\_message](#input\_memory\_usage\_message) | Custom message for PostgreSQL memory monitor | `string` | `""` | no | +| [memory\_usage\_threshold\_critical](#input\_memory\_usage\_threshold\_critical) | PostgreSQL memory usage in percent (critical threshold) | `string` | `"90"` | no | +| [memory\_usage\_threshold\_warning](#input\_memory\_usage\_threshold\_warning) | PostgreSQL memory usage in percent (warning threshold) | `string` | `"80"` | no | +| [memory\_usage\_time\_aggregator](#input\_memory\_usage\_time\_aggregator) | Monitor aggregator for PostgreSQL memory [available values: min, max or avg] | `string` | `"min"` | no | +| [memory\_usage\_timeframe](#input\_memory\_usage\_timeframe) | Monitor timeframe for PostgreSQL memory [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [no\_connection\_enabled](#input\_no\_connection\_enabled) | Flag to enable PostgreSQL status monitor | `string` | `"true"` | no | +| [no\_connection\_extra\_tags](#input\_no\_connection\_extra\_tags) | Extra tags for PostgreSQL status monitor | `list(string)` | `[]` | no | +| [no\_connection\_message](#input\_no\_connection\_message) | Custom message for PostgreSQL no connection monitor | `string` | `""` | no | +| [no\_connection\_time\_aggregator](#input\_no\_connection\_time\_aggregator) | Monitor aggregator for PostgreSQL no connection [available values: min, max or avg] | `string` | `"min"` | no | +| [no\_connection\_timeframe](#input\_no\_connection\_timeframe) | Monitor timeframe for PostgreSQL no connection [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [postgresql\_no\_connection\_no\_data\_timeframe](#input\_postgresql\_no\_connection\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [postgresql\_cpu\_usage\_id](#output\_postgresql\_cpu\_usage\_id) | id for monitor postgresql\_cpu\_usage | +| [postgresql\_free\_storage\_id](#output\_postgresql\_free\_storage\_id) | id for monitor postgresql\_free\_storage | +| [postgresql\_io\_consumption\_id](#output\_postgresql\_io\_consumption\_id) | id for monitor postgresql\_io\_consumption | +| [postgresql\_memory\_usage\_id](#output\_postgresql\_memory\_usage\_id) | id for monitor postgresql\_memory\_usage | +| [postgresql\_no\_connection\_id](#output\_postgresql\_no\_connection\_id) | id for monitor postgresql\_no\_connection | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure/](https://docs.datadoghq.com/integrations/azure/) +You have to search `mysql` diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/postgresql/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/postgresql/inputs.tf new file mode 100755 index 0000000..07512a0 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/postgresql/inputs.tf @@ -0,0 +1,239 @@ +# Global Terraform +variable "environment" { + description = "Architecture environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "postgresql_no_connection_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +# Azure Databases for PostgreSQL Servers specific variables + +variable "cpu_usage_enabled" { + description = "Flag to enable PostgreSQL status monitor" + type = string + default = "true" +} + +variable "cpu_usage_extra_tags" { + description = "Extra tags for PostgreSQL status monitor" + type = list(string) + default = [] +} + +variable "cpu_usage_message" { + description = "Custom message for PostgreSQL CPU monitor" + type = string + default = "" +} + +variable "cpu_usage_time_aggregator" { + description = "Monitor aggregator for PostgreSQL CPU [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cpu_usage_timeframe" { + description = "Monitor timeframe for PostgreSQL CPU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "cpu_usage_threshold_warning" { + description = "PostgreSQL CPU usage in percent (warning threshold)" + default = "80" +} + +variable "cpu_usage_threshold_critical" { + description = "PostgreSQL CPU usage in percent (critical threshold)" + default = "90" +} + +variable "no_connection_enabled" { + description = "Flag to enable PostgreSQL status monitor" + type = string + default = "true" +} + +variable "no_connection_extra_tags" { + description = "Extra tags for PostgreSQL status monitor" + type = list(string) + default = [] +} + +variable "no_connection_message" { + description = "Custom message for PostgreSQL no connection monitor" + type = string + default = "" +} + +variable "no_connection_time_aggregator" { + description = "Monitor aggregator for PostgreSQL no connection [available values: min, max or avg]" + type = string + default = "min" +} + +variable "no_connection_timeframe" { + description = "Monitor timeframe for PostgreSQL no connection [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "free_storage_enabled" { + description = "Flag to enable PostgreSQL status monitor" + type = string + default = "true" +} + +variable "free_storage_extra_tags" { + description = "Extra tags for PostgreSQL status monitor" + type = list(string) + default = [] +} + +variable "free_storage_message" { + description = "Custom message for PostgreSQL Free Storage monitor" + type = string + default = "" +} + +variable "free_storage_time_aggregator" { + description = "Monitor aggregator for PostgreSQL Free Storage [available values: min, max or avg]" + type = string + default = "min" +} + +variable "free_storage_timeframe" { + description = "Monitor timeframe for PostgreSQL Free Storage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "free_storage_threshold_warning" { + description = "PostgreSQL Free Storage remaining in percent (warning threshold)" + default = "20" +} + +variable "free_storage_threshold_critical" { + description = "PostgreSQL Free Storage remaining in percent (critical threshold)" + default = "10" +} + +variable "io_consumption_enabled" { + description = "Flag to enable PostgreSQL status monitor" + type = string + default = "true" +} + +variable "io_consumption_extra_tags" { + description = "Extra tags for PostgreSQL status monitor" + type = list(string) + default = [] +} + +variable "io_consumption_message" { + description = "Custom message for PostgreSQL IO consumption monitor" + type = string + default = "" +} + +variable "io_consumption_time_aggregator" { + description = "Monitor aggregator for PostgreSQL IO consumption [available values: min, max or avg]" + type = string + default = "min" +} + +variable "io_consumption_timeframe" { + description = "Monitor timeframe for PostgreSQL IO consumption [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "io_consumption_threshold_warning" { + description = "PostgreSQL IO consumption in percent (warning threshold)" + default = "80" +} + +variable "io_consumption_threshold_critical" { + description = "PostgreSQL IO consumption in percent (critical threshold)" + default = "90" +} + +variable "memory_usage_enabled" { + description = "Flag to enable PostgreSQL status monitor" + type = string + default = "true" +} + +variable "memory_usage_extra_tags" { + description = "Extra tags for PostgreSQL status monitor" + type = list(string) + default = [] +} + +variable "memory_usage_message" { + description = "Custom message for PostgreSQL memory monitor" + type = string + default = "" +} + +variable "memory_usage_time_aggregator" { + description = "Monitor aggregator for PostgreSQL memory [available values: min, max or avg]" + type = string + default = "min" +} + +variable "memory_usage_timeframe" { + description = "Monitor timeframe for PostgreSQL memory [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "memory_usage_threshold_warning" { + description = "PostgreSQL memory usage in percent (warning threshold)" + default = "80" +} + +variable "memory_usage_threshold_critical" { + description = "PostgreSQL memory usage in percent (critical threshold)" + default = "90" +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/postgresql/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/postgresql/modules.tf new file mode 100755 index 0000000..52a7f41 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/postgresql/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_postgresql" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/postgresql/monitors-postegresql.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/postgresql/monitors-postegresql.tf new file mode 100755 index 0000000..3e96e23 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/postgresql/monitors-postegresql.tf @@ -0,0 +1,146 @@ +resource "datadog_monitor" "postgresql_cpu_usage" { + count = var.cpu_usage_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Postgresql Server CPU usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cpu_usage_message, var.message) + type = "query alert" + + query = < ${var.cpu_usage_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.cpu_usage_threshold_critical + warning = var.cpu_usage_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:postgresql", "team:claranet", "created-by:terraform"], var.cpu_usage_extra_tags) +} + +resource "datadog_monitor" "postgresql_no_connection" { + count = var.no_connection_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Postgresql Server has no connection" + message = coalesce(var.no_connection_message, var.message) + type = "query alert" + + query = < ${var.io_consumption_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.io_consumption_threshold_critical + warning = var.io_consumption_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:postgresql", "team:claranet", "created-by:terraform"], var.io_consumption_extra_tags) +} + +resource "datadog_monitor" "postgresql_memory_usage" { + count = var.memory_usage_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Postgresql Server memory usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.memory_usage_message, var.message) + type = "query alert" + + query = < ${var.memory_usage_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.memory_usage_threshold_critical + warning = var.memory_usage_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:postgresql", "team:claranet", "created-by:terraform"], var.memory_usage_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/postgresql/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/postgresql/outputs.tf new file mode 100755 index 0000000..43af1ce --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/postgresql/outputs.tf @@ -0,0 +1,25 @@ +output "postgresql_cpu_usage_id" { + description = "id for monitor postgresql_cpu_usage" + value = datadog_monitor.postgresql_cpu_usage.*.id +} + +output "postgresql_free_storage_id" { + description = "id for monitor postgresql_free_storage" + value = datadog_monitor.postgresql_free_storage.*.id +} + +output "postgresql_io_consumption_id" { + description = "id for monitor postgresql_io_consumption" + value = datadog_monitor.postgresql_io_consumption.*.id +} + +output "postgresql_memory_usage_id" { + description = "id for monitor postgresql_memory_usage" + value = datadog_monitor.postgresql_memory_usage.*.id +} + +output "postgresql_no_connection_id" { + description = "id for monitor postgresql_no_connection" + value = datadog_monitor.postgresql_no_connection.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/postgresql/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/postgresql/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/postgresql/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/redis/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/redis/README.md new file mode 100755 index 0000000..01991b1 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/redis/README.md @@ -0,0 +1,106 @@ +# CLOUD AZURE REDIS DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-redis" { + source = "claranet/monitors/datadog//cloud/azure/redis" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Redis {{name}} is down +- Redis processor time too high +- Redis server load too high +- Redis too many evictedkeys + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.evictedkeys](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.percent_processor_time](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.server_load](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [evictedkeys\_limit\_enabled](#input\_evictedkeys\_limit\_enabled) | Flag to enable Redis evicted keys monitor | `string` | `"true"` | no | +| [evictedkeys\_limit\_extra\_tags](#input\_evictedkeys\_limit\_extra\_tags) | Extra tags for Redis evicted keys monitor | `list(string)` | `[]` | no | +| [evictedkeys\_limit\_message](#input\_evictedkeys\_limit\_message) | Custom message for Redis evicted keys monitor | `string` | `""` | no | +| [evictedkeys\_limit\_threshold\_critical](#input\_evictedkeys\_limit\_threshold\_critical) | Evicted keys limit (critical threshold) | `number` | `100` | no | +| [evictedkeys\_limit\_threshold\_warning](#input\_evictedkeys\_limit\_threshold\_warning) | Evicted keys limit (warning threshold) | `number` | `0` | no | +| [evictedkeys\_limit\_time\_aggregator](#input\_evictedkeys\_limit\_time\_aggregator) | Monitor aggregator for Redis evicted keys [available values: min, max or avg] | `string` | `"avg"` | no | +| [evictedkeys\_limit\_timeframe](#input\_evictedkeys\_limit\_timeframe) | Monitor timeframe for Redis evicted keys [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a Redis monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [percent\_processor\_time\_enabled](#input\_percent\_processor\_time\_enabled) | Flag to enable Redis processor monitor | `string` | `"true"` | no | +| [percent\_processor\_time\_extra\_tags](#input\_percent\_processor\_time\_extra\_tags) | Extra tags for Redis processor monitor | `list(string)` | `[]` | no | +| [percent\_processor\_time\_message](#input\_percent\_processor\_time\_message) | Custom message for Redis processor monitor | `string` | `""` | no | +| [percent\_processor\_time\_threshold\_critical](#input\_percent\_processor\_time\_threshold\_critical) | Processor time percent (critical threshold) | `number` | `80` | no | +| [percent\_processor\_time\_threshold\_warning](#input\_percent\_processor\_time\_threshold\_warning) | Processor time percent (warning threshold) | `number` | `60` | no | +| [percent\_processor\_time\_time\_aggregator](#input\_percent\_processor\_time\_time\_aggregator) | Monitor aggregator for Redis processor [available values: min, max or avg] | `string` | `"min"` | no | +| [percent\_processor\_time\_timeframe](#input\_percent\_processor\_time\_timeframe) | Monitor timeframe for Redis processor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [server\_load\_rate\_enabled](#input\_server\_load\_rate\_enabled) | Flag to enable Redis server load monitor | `string` | `"true"` | no | +| [server\_load\_rate\_extra\_tags](#input\_server\_load\_rate\_extra\_tags) | Extra tags for Redis server load monitor | `list(string)` | `[]` | no | +| [server\_load\_rate\_message](#input\_server\_load\_rate\_message) | Custom message for Redis server load monitor | `string` | `""` | no | +| [server\_load\_rate\_threshold\_critical](#input\_server\_load\_rate\_threshold\_critical) | Server CPU load rate (critical threshold) | `number` | `90` | no | +| [server\_load\_rate\_threshold\_warning](#input\_server\_load\_rate\_threshold\_warning) | Server CPU load rate (warning threshold) | `number` | `70` | no | +| [server\_load\_rate\_time\_aggregator](#input\_server\_load\_rate\_time\_aggregator) | Monitor aggregator for Redis server load [available values: min, max or avg] | `string` | `"min"` | no | +| [server\_load\_rate\_timeframe](#input\_server\_load\_rate\_timeframe) | Monitor timeframe for Redis server load [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable Redis status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for Redis status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for Redis status monitor | `string` | `""` | no | +| [status\_no\_data\_timeframe](#input\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for Redis status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for Redis status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [evictedkeys\_id](#output\_evictedkeys\_id) | id for monitor evictedkeys | +| [percent\_processor\_time\_id](#output\_percent\_processor\_time\_id) | id for monitor percent\_processor\_time | +| [server\_load\_id](#output\_server\_load\_id) | id for monitor server\_load | +| [status\_id](#output\_status\_id) | id for monitor status | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure_redis_cache/](https://docs.datadoghq.com/integrations/azure_redis_cache/) + +Azure Redis metrics documentation: [https://docs.microsoft.com/en-us/azure/redis-cache/cache-how-to-monitor](https://docs.microsoft.com/en-us/azure/redis-cache/cache-how-to-monitor) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/redis/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/redis/inputs.tf new file mode 100755 index 0000000..271b2c5 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/redis/inputs.tf @@ -0,0 +1,204 @@ +# Global Terraform +variable "environment" { + description = "Architecture environment" + type = string +} + +# Global DataDog +variable "message" { + description = "Message sent when a Redis monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Azure Redis specific variables + +variable "status_enabled" { + description = "Flag to enable Redis status monitor" + type = string + default = "true" +} + +variable "status_extra_tags" { + description = "Extra tags for Redis status monitor" + type = list(string) + default = [] +} + +variable "status_message" { + description = "Custom message for Redis status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for Redis status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for Redis status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "evictedkeys_limit_enabled" { + description = "Flag to enable Redis evicted keys monitor" + type = string + default = "true" +} + +variable "evictedkeys_limit_extra_tags" { + description = "Extra tags for Redis evicted keys monitor" + type = list(string) + default = [] +} + +variable "evictedkeys_limit_message" { + description = "Custom message for Redis evicted keys monitor" + type = string + default = "" +} + +variable "evictedkeys_limit_time_aggregator" { + description = "Monitor aggregator for Redis evicted keys [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "evictedkeys_limit_timeframe" { + description = "Monitor timeframe for Redis evicted keys [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "evictedkeys_limit_threshold_warning" { + description = "Evicted keys limit (warning threshold)" + default = 0 +} + +variable "evictedkeys_limit_threshold_critical" { + description = "Evicted keys limit (critical threshold)" + default = 100 +} + +variable "percent_processor_time_enabled" { + description = "Flag to enable Redis processor monitor" + type = string + default = "true" +} + +variable "percent_processor_time_extra_tags" { + description = "Extra tags for Redis processor monitor" + type = list(string) + default = [] +} + +variable "percent_processor_time_message" { + description = "Custom message for Redis processor monitor" + type = string + default = "" +} + +variable "percent_processor_time_time_aggregator" { + description = "Monitor aggregator for Redis processor [available values: min, max or avg]" + type = string + default = "min" +} + +variable "percent_processor_time_timeframe" { + description = "Monitor timeframe for Redis processor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "percent_processor_time_threshold_critical" { + description = "Processor time percent (critical threshold)" + default = 80 +} + +variable "percent_processor_time_threshold_warning" { + description = "Processor time percent (warning threshold)" + default = 60 +} + +variable "server_load_rate_enabled" { + description = "Flag to enable Redis server load monitor" + type = string + default = "true" +} + +variable "server_load_rate_extra_tags" { + description = "Extra tags for Redis server load monitor" + type = list(string) + default = [] +} + +variable "server_load_rate_message" { + description = "Custom message for Redis server load monitor" + type = string + default = "" +} + +variable "server_load_rate_time_aggregator" { + description = "Monitor aggregator for Redis server load [available values: min, max or avg]" + type = string + default = "min" +} + +variable "server_load_rate_timeframe" { + description = "Monitor timeframe for Redis server load [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "server_load_rate_threshold_critical" { + description = "Server CPU load rate (critical threshold)" + default = 90 +} + +variable "server_load_rate_threshold_warning" { + description = "Server CPU load rate (warning threshold)" + default = 70 +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/redis/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/redis/modules.tf new file mode 100755 index 0000000..1c038f7 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/redis/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_redis" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/redis/monitors-azure-redis.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/redis/monitors-azure-redis.tf new file mode 100755 index 0000000..bf6c5ea --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/redis/monitors-azure-redis.tf @@ -0,0 +1,116 @@ +resource "datadog_monitor" "status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Redis {{name}} is down" + message = coalesce(var.status_message, var.message) + type = "query alert" + + query = < ${var.evictedkeys_limit_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.evictedkeys_limit_threshold_warning + critical = var.evictedkeys_limit_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:redis", "team:claranet", "created-by:terraform"], var.evictedkeys_limit_extra_tags) +} + +resource "datadog_monitor" "percent_processor_time" { + count = var.percent_processor_time_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Redis processor time too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.percent_processor_time_message, var.message) + type = "query alert" + + query = < ${var.percent_processor_time_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.percent_processor_time_threshold_warning + critical = var.percent_processor_time_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:redis", "team:claranet", "created-by:terraform"], var.percent_processor_time_extra_tags) +} + +resource "datadog_monitor" "server_load" { + count = var.server_load_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Redis server load too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.server_load_rate_message, var.message) + type = "query alert" + + query = < ${var.server_load_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.server_load_rate_threshold_warning + critical = var.server_load_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:redis", "team:claranet", "created-by:terraform"], var.server_load_rate_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/redis/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/redis/outputs.tf new file mode 100755 index 0000000..de308e6 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/redis/outputs.tf @@ -0,0 +1,20 @@ +output "evictedkeys_id" { + description = "id for monitor evictedkeys" + value = datadog_monitor.evictedkeys.*.id +} + +output "percent_processor_time_id" { + description = "id for monitor percent_processor_time" + value = datadog_monitor.percent_processor_time.*.id +} + +output "server_load_id" { + description = "id for monitor server_load" + value = datadog_monitor.server_load.*.id +} + +output "status_id" { + description = "id for monitor status" + value = datadog_monitor.status.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/redis/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/redis/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/redis/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/serverfarms/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/serverfarms/README.md new file mode 100755 index 0000000..0a6db2a --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/serverfarms/README.md @@ -0,0 +1,92 @@ +# CLOUD AZURE SERVERFARMS DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-serverfarms" { + source = "claranet/monitors/datadog//cloud/azure/serverfarms" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Serverfarm CPU percentage is too high +- Serverfarm is down +- Serverfarm memory percentage is too high + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cpu_percentage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.memory_percentage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_percentage\_enabled](#input\_cpu\_percentage\_enabled) | Flag to enable the serverfarms cpu\_percentage monitor | `string` | `"true"` | no | +| [cpu\_percentage\_extra\_tags](#input\_cpu\_percentage\_extra\_tags) | Extra tags for serverfarms cpu\_percentage monitor | `list(string)` | `[]` | no | +| [cpu\_percentage\_message](#input\_cpu\_percentage\_message) | Custom message for serverfarm cpu\_percentage monitor | `string` | `""` | no | +| [cpu\_percentage\_threshold\_critical](#input\_cpu\_percentage\_threshold\_critical) | CPU percentage (critical threshold) | `number` | `95` | no | +| [cpu\_percentage\_threshold\_warning](#input\_cpu\_percentage\_threshold\_warning) | CPU percentage (warning threshold) | `number` | `90` | no | +| [cpu\_percentage\_time\_aggregator](#input\_cpu\_percentage\_time\_aggregator) | Monitor aggregator for serverfarms cpu\_percentage [available values: min, max or avg] | `string` | `"min"` | no | +| [cpu\_percentage\_timeframe](#input\_cpu\_percentage\_timeframe) | Monitor timeframe for serverfarms cpu\_percentage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_10m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [memory\_percentage\_enabled](#input\_memory\_percentage\_enabled) | Flag to enable the serverfarms memory\_percentage monitor | `string` | `"true"` | no | +| [memory\_percentage\_extra\_tags](#input\_memory\_percentage\_extra\_tags) | Extra tags for serverfarms memory\_percentage monitor | `list(string)` | `[]` | no | +| [memory\_percentage\_message](#input\_memory\_percentage\_message) | Custom message for serverfarm memory\_percentage monitor | `string` | `""` | no | +| [memory\_percentage\_threshold\_critical](#input\_memory\_percentage\_threshold\_critical) | Memory percentage (critical threshold) | `number` | `95` | no | +| [memory\_percentage\_threshold\_warning](#input\_memory\_percentage\_threshold\_warning) | Memory percentage (warning threshold) | `number` | `90` | no | +| [memory\_percentage\_time\_aggregator](#input\_memory\_percentage\_time\_aggregator) | Monitor aggregator for serverfarms memory\_percentage [available values: min, max or avg] | `string` | `"min"` | no | +| [memory\_percentage\_timeframe](#input\_memory\_percentage\_timeframe) | Monitor timeframe for serverfarms memory\_percentage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when a serverfarms monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable the serverfarms status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for serverfarms status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for serverfarm status monitor | `string` | `""` | no | +| [status\_no\_data\_timeframe](#input\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for serverfarms status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for serverfarms status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cpu\_percentage\_id](#output\_cpu\_percentage\_id) | id for monitor cpu\_percentage | +| [memory\_percentage\_id](#output\_memory\_percentage\_id) | id for monitor memory\_percentage | +| [status\_id](#output\_status\_id) | id for monitor status | +## Related documentation + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/serverfarms/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/serverfarms/inputs.tf new file mode 100755 index 0000000..5125827 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/serverfarms/inputs.tf @@ -0,0 +1,162 @@ +# Global Terraform +variable "environment" { + description = "Architecture environment" + type = string +} + +# Global DataDog +variable "message" { + description = "Message sent when a serverfarms monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +# Azure serverfarms specific variables + +# Status +variable "status_enabled" { + description = "Flag to enable the serverfarms status monitor" + type = string + default = "true" +} + +variable "status_message" { + description = "Custom message for serverfarm status monitor" + type = string + default = "" +} + +variable "status_extra_tags" { + description = "Extra tags for serverfarms status monitor" + type = list(string) + default = [] +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for serverfarms status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for serverfarms status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +# CPU percentage +variable "cpu_percentage_enabled" { + description = "Flag to enable the serverfarms cpu_percentage monitor" + type = string + default = "true" +} + +variable "cpu_percentage_message" { + description = "Custom message for serverfarm cpu_percentage monitor" + type = string + default = "" +} + +variable "cpu_percentage_extra_tags" { + description = "Extra tags for serverfarms cpu_percentage monitor" + type = list(string) + default = [] +} + +variable "cpu_percentage_time_aggregator" { + description = "Monitor aggregator for serverfarms cpu_percentage [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cpu_percentage_timeframe" { + description = "Monitor timeframe for serverfarms cpu_percentage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_10m" +} + +variable "cpu_percentage_threshold_critical" { + description = "CPU percentage (critical threshold)" + default = 95 +} + +variable "cpu_percentage_threshold_warning" { + description = "CPU percentage (warning threshold)" + default = 90 +} + +# Memory percentage +variable "memory_percentage_enabled" { + description = "Flag to enable the serverfarms memory_percentage monitor" + type = string + default = "true" +} + +variable "memory_percentage_message" { + description = "Custom message for serverfarm memory_percentage monitor" + type = string + default = "" +} + +variable "memory_percentage_extra_tags" { + description = "Extra tags for serverfarms memory_percentage monitor" + type = list(string) + default = [] +} + +variable "memory_percentage_time_aggregator" { + description = "Monitor aggregator for serverfarms memory_percentage [available values: min, max or avg]" + type = string + default = "min" +} + +variable "memory_percentage_timeframe" { + description = "Monitor timeframe for serverfarms memory_percentage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "memory_percentage_threshold_critical" { + description = "Memory percentage (critical threshold)" + default = 95 +} + +variable "memory_percentage_threshold_warning" { + description = "Memory percentage (warning threshold)" + default = 90 +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/serverfarms/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/serverfarms/modules.tf new file mode 100755 index 0000000..ed11dfa --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/serverfarms/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_serverfarms" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/serverfarms/monitors-azure-serverfarms.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/serverfarms/monitors-azure-serverfarms.tf new file mode 100755 index 0000000..3e56420 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/serverfarms/monitors-azure-serverfarms.tf @@ -0,0 +1,86 @@ +resource "datadog_monitor" "status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Serverfarm is down" + message = coalesce(var.status_message, var.message) + type = "query alert" + + query = < ${var.cpu_percentage_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.cpu_percentage_threshold_warning + critical = var.cpu_percentage_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:serverfarms", "team:claranet", "created-by:terraform"], var.cpu_percentage_extra_tags) +} + +resource "datadog_monitor" "memory_percentage" { + count = var.memory_percentage_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Serverfarm memory percentage is too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.memory_percentage_message, var.message) + type = "query alert" + + query = < ${var.memory_percentage_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.memory_percentage_threshold_warning + critical = var.memory_percentage_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:serverfarms", "team:claranet", "created-by:terraform"], var.memory_percentage_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/serverfarms/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/serverfarms/outputs.tf new file mode 100755 index 0000000..6ab4b6c --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/serverfarms/outputs.tf @@ -0,0 +1,15 @@ +output "cpu_percentage_id" { + description = "id for monitor cpu_percentage" + value = datadog_monitor.cpu_percentage.*.id +} + +output "memory_percentage_id" { + description = "id for monitor memory_percentage" + value = datadog_monitor.memory_percentage.*.id +} + +output "status_id" { + description = "id for monitor status" + value = datadog_monitor.status.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/serverfarms/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/serverfarms/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/serverfarms/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/servicebus/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/servicebus/README.md new file mode 100755 index 0000000..9b9c6f3 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/servicebus/README.md @@ -0,0 +1,105 @@ +# CLOUD AZURE SERVICEBUS DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-servicebus" { + source = "claranet/monitors/datadog//cloud/azure/servicebus" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Service Bus has no active connection +- Service Bus is down +- Service Bus server errors rate is high +- Service Bus user errors rate is high + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.service_bus_no_active_connections](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.service_bus_server_errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.service_bus_user_errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.servicebus_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [no\_active\_connections\_enabled](#input\_no\_active\_connections\_enabled) | Flag to enable Service Bus no active connections monitor | `string` | `"true"` | no | +| [no\_active\_connections\_extra\_tags](#input\_no\_active\_connections\_extra\_tags) | Extra tags for Service Bus no active connections monitor | `list(string)` | `[]` | no | +| [no\_active\_connections\_message](#input\_no\_active\_connections\_message) | Custom message for Service Bus no active connections monitor | `string` | `""` | no | +| [no\_active\_connections\_time\_aggregator](#input\_no\_active\_connections\_time\_aggregator) | Monitor aggregator for Service Bus no active connections [available values: min, max or avg] | `string` | `"max"` | no | +| [no\_active\_connections\_timeframe](#input\_no\_active\_connections\_timeframe) | Monitor timeframe for Service Bus no active connections [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [server\_errors\_enabled](#input\_server\_errors\_enabled) | Flag to enable Service Bus server errors monitor | `string` | `"true"` | no | +| [server\_errors\_extra\_tags](#input\_server\_errors\_extra\_tags) | Extra tags for Service Bus server errors monitor | `list(string)` | `[]` | no | +| [server\_errors\_message](#input\_server\_errors\_message) | Custom message for Service Bus server errors monitor | `string` | `""` | no | +| [server\_errors\_threshold\_critical](#input\_server\_errors\_threshold\_critical) | Critical threshold for Service Bus server errors monitor | `number` | `90` | no | +| [server\_errors\_threshold\_warning](#input\_server\_errors\_threshold\_warning) | Warning threshold for Service Bus server errors monitor | `number` | `50` | no | +| [server\_errors\_time\_aggregator](#input\_server\_errors\_time\_aggregator) | Monitor aggregator for Service Bus server errors [available values: min, max or avg] | `string` | `"min"` | no | +| [server\_errors\_timeframe](#input\_server\_errors\_timeframe) | Monitor timeframe for Service Bus server errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [servicebus\_status\_no\_data\_timeframe](#input\_servicebus\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable Service Bus status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for Service Bus status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for Service Bus status monitor | `string` | `""` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for Service Bus status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for Service Bus status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [user\_errors\_enabled](#input\_user\_errors\_enabled) | Flag to enable Service Bus user errors monitor | `string` | `"true"` | no | +| [user\_errors\_extra\_tags](#input\_user\_errors\_extra\_tags) | Extra tags for Service Bus user errors monitor | `list(string)` | `[]` | no | +| [user\_errors\_message](#input\_user\_errors\_message) | Custom message for Service Bus user errors monitor | `string` | `""` | no | +| [user\_errors\_threshold\_critical](#input\_user\_errors\_threshold\_critical) | Critical threshold for Service Bus user errors monitor | `number` | `90` | no | +| [user\_errors\_threshold\_warning](#input\_user\_errors\_threshold\_warning) | Warning threshold for Service Bus user errors monitor | `number` | `50` | no | +| [user\_errors\_time\_aggregator](#input\_user\_errors\_time\_aggregator) | Monitor aggregator for Service Bus user errors [available values: min, max or avg] | `string` | `"min"` | no | +| [user\_errors\_timeframe](#input\_user\_errors\_timeframe) | Monitor timeframe for Service Bus user errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [service\_bus\_no\_active\_connections\_id](#output\_service\_bus\_no\_active\_connections\_id) | id for monitor service\_bus\_no\_active\_connections | +| [service\_bus\_server\_errors\_id](#output\_service\_bus\_server\_errors\_id) | id for monitor service\_bus\_server\_errors | +| [service\_bus\_user\_errors\_id](#output\_service\_bus\_user\_errors\_id) | id for monitor service\_bus\_user\_errors | +| [servicebus\_status\_id](#output\_servicebus\_status\_id) | id for monitor servicebus\_status | +## Related documentation + +DataDog documentation : [https://docs.datadoghq.com/integrations/azure/](https://docs.datadoghq.com/integrations/azure/) +You must search `servicebus`, there is no integration for now. + +Azure metrics documentation : [https://docs.microsoft.com/fr-fr/azure/monitoring-and-diagnostics/monitoring-supported-metrics#microsoftservicebusnamespaces](https://docs.microsoft.com/fr-fr/azure/monitoring-and-diagnostics/monitoring-supported-metrics#microsoftservicebusnamespaces) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/servicebus/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/servicebus/inputs.tf new file mode 100755 index 0000000..cf594ed --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/servicebus/inputs.tf @@ -0,0 +1,192 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "servicebus_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Azure Service Bus specific variables +variable "status_enabled" { + description = "Flag to enable Service Bus status monitor" + type = string + default = "true" +} + +variable "status_extra_tags" { + description = "Extra tags for Service Bus status monitor" + type = list(string) + default = [] +} + +variable "status_message" { + description = "Custom message for Service Bus status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for Service Bus status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for Service Bus status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + default = "last_5m" +} + +variable "no_active_connections_enabled" { + description = "Flag to enable Service Bus no active connections monitor" + type = string + default = "true" +} + +variable "no_active_connections_extra_tags" { + description = "Extra tags for Service Bus no active connections monitor" + type = list(string) + default = [] +} + +variable "no_active_connections_message" { + description = "Custom message for Service Bus no active connections monitor" + type = string + default = "" +} + +variable "no_active_connections_time_aggregator" { + description = "Monitor aggregator for Service Bus no active connections [available values: min, max or avg]" + type = string + default = "max" +} + +variable "no_active_connections_timeframe" { + description = "Monitor timeframe for Service Bus no active connections [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "server_errors_message" { + description = "Custom message for Service Bus server errors monitor" + type = string + default = "" +} + +variable "server_errors_enabled" { + description = "Flag to enable Service Bus server errors monitor" + type = string + default = "true" +} + +variable "server_errors_extra_tags" { + description = "Extra tags for Service Bus server errors monitor" + type = list(string) + default = [] +} + +variable "server_errors_time_aggregator" { + description = "Monitor aggregator for Service Bus server errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "server_errors_timeframe" { + description = "Monitor timeframe for Service Bus server errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "server_errors_threshold_critical" { + description = "Critical threshold for Service Bus server errors monitor" + default = 90 +} + +variable "server_errors_threshold_warning" { + description = "Warning threshold for Service Bus server errors monitor" + default = 50 +} + +variable "user_errors_message" { + description = "Custom message for Service Bus user errors monitor" + type = string + default = "" +} + +variable "user_errors_enabled" { + description = "Flag to enable Service Bus user errors monitor" + type = string + default = "true" +} + +variable "user_errors_extra_tags" { + description = "Extra tags for Service Bus user errors monitor" + type = list(string) + default = [] +} + +variable "user_errors_time_aggregator" { + description = "Monitor aggregator for Service Bus user errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "user_errors_timeframe" { + description = "Monitor timeframe for Service Bus user errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "user_errors_threshold_critical" { + description = "Critical threshold for Service Bus user errors monitor" + default = 90 +} + +variable "user_errors_threshold_warning" { + description = "Warning threshold for Service Bus user errors monitor" + default = 50 +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/servicebus/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/servicebus/modules.tf new file mode 100755 index 0000000..4abc459 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/servicebus/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_servicebus" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/servicebus/monitors-service-bus.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/servicebus/monitors-service-bus.tf new file mode 100755 index 0000000..4443ee7 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/servicebus/monitors-service-bus.tf @@ -0,0 +1,113 @@ +resource "datadog_monitor" "servicebus_status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Service Bus is down" + message = coalesce(var.status_message, var.message) + type = "query alert" + + query = < ${var.user_errors_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.user_errors_threshold_critical + warning = var.user_errors_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:servicebus", "team:claranet", "created-by:terraform"], var.user_errors_extra_tags) +} + +resource "datadog_monitor" "service_bus_server_errors" { + count = var.server_errors_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Service Bus server errors rate is high {{#is_alert}}{{comparator}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{comparator}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.server_errors_message, var.message) + type = "query alert" + + query = < ${var.server_errors_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.server_errors_threshold_critical + warning = var.server_errors_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:servicebus", "team:claranet", "created-by:terraform"], var.server_errors_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/servicebus/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/servicebus/outputs.tf new file mode 100755 index 0000000..5344f91 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/servicebus/outputs.tf @@ -0,0 +1,20 @@ +output "service_bus_no_active_connections_id" { + description = "id for monitor service_bus_no_active_connections" + value = datadog_monitor.service_bus_no_active_connections.*.id +} + +output "service_bus_server_errors_id" { + description = "id for monitor service_bus_server_errors" + value = datadog_monitor.service_bus_server_errors.*.id +} + +output "service_bus_user_errors_id" { + description = "id for monitor service_bus_user_errors" + value = datadog_monitor.service_bus_user_errors.*.id +} + +output "servicebus_status_id" { + description = "id for monitor servicebus_status" + value = datadog_monitor.servicebus_status.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/servicebus/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/servicebus/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/servicebus/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-database/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-database/README.md new file mode 100755 index 0000000..104b8ba --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-database/README.md @@ -0,0 +1,115 @@ +# CLOUD AZURE SQL-DATABASE DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-sql-database" { + source = "claranet/monitors/datadog//cloud/azure/sql-database" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- SQL Database CPU too high +- SQL Database Deadlocks too high +- SQL Database DTU Consumption too high +- SQL Database high disk usage +- SQL Database is down + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.sql-database_cpu](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.sql-database_deadlocks_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.sql-database_dtu_consumption_high](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.sql-database_free_space_low](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_enabled](#input\_cpu\_enabled) | Flag to enable SQL CPU monitor | `string` | `"true"` | no | +| [cpu\_extra\_tags](#input\_cpu\_extra\_tags) | Extra tags for SQL CPU monitor | `list(string)` | `[]` | no | +| [cpu\_message](#input\_cpu\_message) | Custom message for SQL CPU monitor | `string` | `""` | no | +| [cpu\_threshold\_critical](#input\_cpu\_threshold\_critical) | CPU usage in percent (critical threshold) | `string` | `"90"` | no | +| [cpu\_threshold\_warning](#input\_cpu\_threshold\_warning) | CPU usage in percent (warning threshold) | `string` | `"80"` | no | +| [cpu\_time\_aggregator](#input\_cpu\_time\_aggregator) | Monitor aggregator for SQL CPU [available values: min, max or avg] | `string` | `"min"` | no | +| [cpu\_timeframe](#input\_cpu\_timeframe) | Monitor timeframe for SQL CPU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [deadlock\_enabled](#input\_deadlock\_enabled) | Flag to enable SQL Deadlock monitor | `string` | `"true"` | no | +| [deadlock\_extra\_tags](#input\_deadlock\_extra\_tags) | Extra tags for SQL Deadlock monitor | `list(string)` | `[]` | no | +| [deadlock\_message](#input\_deadlock\_message) | Custom message for SQL Deadlock monitor | `string` | `""` | no | +| [deadlock\_threshold\_critical](#input\_deadlock\_threshold\_critical) | Amount of Deadlocks (critical threshold) | `string` | `"1"` | no | +| [deadlock\_timeframe](#input\_deadlock\_timeframe) | Monitor timeframe for SQL Deadlock [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [diskspace\_enabled](#input\_diskspace\_enabled) | Flag to enable SQL disk space monitor | `string` | `"true"` | no | +| [diskspace\_extra\_tags](#input\_diskspace\_extra\_tags) | Extra tags for SQL disk space monitor | `list(string)` | `[]` | no | +| [diskspace\_message](#input\_diskspace\_message) | Custom message for SQL disk space monitor | `string` | `""` | no | +| [diskspace\_threshold\_critical](#input\_diskspace\_threshold\_critical) | Disk space used in percent (critical threshold) | `string` | `"90"` | no | +| [diskspace\_threshold\_warning](#input\_diskspace\_threshold\_warning) | Disk space used in percent (warning threshold) | `string` | `"80"` | no | +| [diskspace\_time\_aggregator](#input\_diskspace\_time\_aggregator) | Monitor aggregator for SQL disk space [available values: min, max or avg] | `string` | `"max"` | no | +| [diskspace\_timeframe](#input\_diskspace\_timeframe) | Monitor timeframe for SQL disk space [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [dtu\_enabled](#input\_dtu\_enabled) | Flag to enable SQL DTU monitor | `string` | `"true"` | no | +| [dtu\_extra\_tags](#input\_dtu\_extra\_tags) | Extra tags for SQL DTU monitor | `list(string)` | `[]` | no | +| [dtu\_message](#input\_dtu\_message) | Custom message for SQL DTU monitor | `string` | `""` | no | +| [dtu\_threshold\_critical](#input\_dtu\_threshold\_critical) | Amount of DTU used (critical threshold) | `string` | `"90"` | no | +| [dtu\_threshold\_warning](#input\_dtu\_threshold\_warning) | Amount of DTU used (warning threshold) | `string` | `"85"` | no | +| [dtu\_time\_aggregator](#input\_dtu\_time\_aggregator) | Monitor aggregator for SQL DTU [available values: min, max or avg] | `string` | `"avg"` | no | +| [dtu\_timeframe](#input\_dtu\_timeframe) | Monitor timeframe for SQL DTU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable Redis status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for Redis status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for Redis status monitor | `string` | `""` | no | +| [status\_no\_data\_timeframe](#input\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for Redis status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for Redis status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [sql-database\_cpu\_id](#output\_sql-database\_cpu\_id) | id for monitor sql-database\_cpu | +| [sql-database\_deadlocks\_count\_id](#output\_sql-database\_deadlocks\_count\_id) | id for monitor sql-database\_deadlocks\_count | +| [sql-database\_dtu\_consumption\_high\_id](#output\_sql-database\_dtu\_consumption\_high\_id) | id for monitor sql-database\_dtu\_consumption\_high | +| [sql-database\_free\_space\_low\_id](#output\_sql-database\_free\_space\_low\_id) | id for monitor sql-database\_free\_space\_low | +| [status\_id](#output\_status\_id) | id for monitor status | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure_sql_database/](https://docs.datadoghq.com/integrations/azure_sql_database/) + +Azure SQL Database metrics documentation: [https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-supported#microsoftsqlserversdatabases](https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-supported#microsoftsqlserversdatabases) + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-database/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-database/inputs.tf new file mode 100755 index 0000000..6fffd14 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-database/inputs.tf @@ -0,0 +1,233 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Azure SQL Database specific variables + +variable "status_enabled" { + description = "Flag to enable Redis status monitor" + type = string + default = "true" +} + +variable "status_extra_tags" { + description = "Extra tags for Redis status monitor" + type = list(string) + default = [] +} + +variable "status_message" { + description = "Custom message for Redis status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for Redis status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for Redis status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "cpu_enabled" { + description = "Flag to enable SQL CPU monitor" + type = string + default = "true" +} + +variable "cpu_extra_tags" { + description = "Extra tags for SQL CPU monitor" + type = list(string) + default = [] +} + +variable "cpu_message" { + description = "Custom message for SQL CPU monitor" + type = string + default = "" +} + +variable "cpu_time_aggregator" { + description = "Monitor aggregator for SQL CPU [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cpu_timeframe" { + description = "Monitor timeframe for SQL CPU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "cpu_threshold_warning" { + description = "CPU usage in percent (warning threshold)" + default = "80" +} + +variable "cpu_threshold_critical" { + description = "CPU usage in percent (critical threshold)" + default = "90" +} + +variable "diskspace_enabled" { + description = "Flag to enable SQL disk space monitor" + type = string + default = "true" +} + +variable "diskspace_extra_tags" { + description = "Extra tags for SQL disk space monitor" + type = list(string) + default = [] +} + +variable "diskspace_message" { + description = "Custom message for SQL disk space monitor" + type = string + default = "" +} + +variable "diskspace_time_aggregator" { + description = "Monitor aggregator for SQL disk space [available values: min, max or avg]" + type = string + default = "max" +} + +variable "diskspace_timeframe" { + description = "Monitor timeframe for SQL disk space [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "diskspace_threshold_warning" { + description = "Disk space used in percent (warning threshold)" + default = "80" +} + +variable "diskspace_threshold_critical" { + description = "Disk space used in percent (critical threshold)" + default = "90" +} + +variable "dtu_enabled" { + description = "Flag to enable SQL DTU monitor" + type = string + default = "true" +} + +variable "dtu_extra_tags" { + description = "Extra tags for SQL DTU monitor" + type = list(string) + default = [] +} + +variable "dtu_message" { + description = "Custom message for SQL DTU monitor" + type = string + default = "" +} + +variable "dtu_time_aggregator" { + description = "Monitor aggregator for SQL DTU [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "dtu_timeframe" { + description = "Monitor timeframe for SQL DTU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "dtu_threshold_warning" { + description = "Amount of DTU used (warning threshold)" + default = "85" +} + +variable "dtu_threshold_critical" { + description = "Amount of DTU used (critical threshold)" + default = "90" +} + +variable "deadlock_enabled" { + description = "Flag to enable SQL Deadlock monitor" + type = string + default = "true" +} + +variable "deadlock_extra_tags" { + description = "Extra tags for SQL Deadlock monitor" + type = list(string) + default = [] +} + +variable "deadlock_message" { + description = "Custom message for SQL Deadlock monitor" + type = string + default = "" +} + +variable "deadlock_timeframe" { + description = "Monitor timeframe for SQL Deadlock [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "deadlock_threshold_critical" { + description = "Amount of Deadlocks (critical threshold)" + default = "1" +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-database/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-database/modules.tf new file mode 100755 index 0000000..6f0c6de --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-database/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_sql-database" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-database/monitors-sql-database.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-database/monitors-sql-database.tf new file mode 100755 index 0000000..f608ef0 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-database/monitors-sql-database.tf @@ -0,0 +1,145 @@ +resource "datadog_monitor" "status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] SQL Database is down" + message = coalesce(var.status_message, var.message) + type = "query alert" + + query = < ${var.cpu_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.cpu_threshold_critical + warning = var.cpu_threshold_warning + } + + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:sql-database", "team:claranet", "created-by:terraform"], var.cpu_extra_tags) +} + +resource "datadog_monitor" "sql-database_free_space_low" { + count = var.diskspace_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] SQL Database high disk usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.diskspace_message, var.message) + type = "query alert" + + query = < ${var.diskspace_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.diskspace_threshold_warning + critical = var.diskspace_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:sql-database", "team:claranet", "created-by:terraform"], var.diskspace_extra_tags) +} + +resource "datadog_monitor" "sql-database_dtu_consumption_high" { + count = var.dtu_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] SQL Database DTU Consumption too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.dtu_message, var.message) + type = "query alert" + + query = < ${var.dtu_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.dtu_threshold_warning + critical = var.dtu_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:sql-database", "team:claranet", "created-by:terraform"], var.dtu_extra_tags) +} + +resource "datadog_monitor" "sql-database_deadlocks_count" { + count = var.deadlock_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] SQL Database Deadlocks too high {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.deadlock_message, var.message) + type = "query alert" + + query = < ${var.deadlock_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.deadlock_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:sql-database", "team:claranet", "created-by:terraform"], var.deadlock_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-database/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-database/outputs.tf new file mode 100755 index 0000000..add5c74 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-database/outputs.tf @@ -0,0 +1,25 @@ +output "sql-database_cpu_id" { + description = "id for monitor sql-database_cpu" + value = datadog_monitor.sql-database_cpu.*.id +} + +output "sql-database_deadlocks_count_id" { + description = "id for monitor sql-database_deadlocks_count" + value = datadog_monitor.sql-database_deadlocks_count.*.id +} + +output "sql-database_dtu_consumption_high_id" { + description = "id for monitor sql-database_dtu_consumption_high" + value = datadog_monitor.sql-database_dtu_consumption_high.*.id +} + +output "sql-database_free_space_low_id" { + description = "id for monitor sql-database_free_space_low" + value = datadog_monitor.sql-database_free_space_low.*.id +} + +output "status_id" { + description = "id for monitor status" + value = datadog_monitor.status.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-database/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-database/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-database/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-elasticpool/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-elasticpool/README.md new file mode 100755 index 0000000..4bbf3c5 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-elasticpool/README.md @@ -0,0 +1,98 @@ +# CLOUD AZURE SQL-ELASTICPOOL DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-sql-elasticpool" { + source = "claranet/monitors/datadog//cloud/azure/sql-elasticpool" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- SQL Elastic Pool CPU too high +- SQL Elastic Pool DTU Consumption too high +- SQL Elastic Pool high disk usage + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.sql_elasticpool_cpu](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.sql_elasticpool_dtu_consumption_high](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.sql_elasticpool_free_space_low](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_enabled](#input\_cpu\_enabled) | Flag to enable SQL Elastic Pool CPU monitor | `string` | `"true"` | no | +| [cpu\_extra\_tags](#input\_cpu\_extra\_tags) | Extra tags for SQL Elastic Pool CPU monitor | `list(string)` | `[]` | no | +| [cpu\_message](#input\_cpu\_message) | Custom message for SQL Elastic Pool CPU monitor | `string` | `""` | no | +| [cpu\_threshold\_critical](#input\_cpu\_threshold\_critical) | CPU usage in percent (critical threshold) | `string` | `"90"` | no | +| [cpu\_threshold\_warning](#input\_cpu\_threshold\_warning) | CPU usage in percent (warning threshold) | `string` | `"80"` | no | +| [cpu\_time\_aggregator](#input\_cpu\_time\_aggregator) | Monitor aggregator for SQL Elastic Pool CPU [available values: min, max or avg] | `string` | `"min"` | no | +| [cpu\_timeframe](#input\_cpu\_timeframe) | Monitor timeframe for SQL Elastic Pool CPU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [diskspace\_enabled](#input\_diskspace\_enabled) | Flag to enable SQL Elastic Pool disk space monitor | `string` | `"true"` | no | +| [diskspace\_extra\_tags](#input\_diskspace\_extra\_tags) | Extra tags for SQL Elastic Pool disk space monitor | `list(string)` | `[]` | no | +| [diskspace\_message](#input\_diskspace\_message) | Custom message for SQL Elastic Pool disk space monitor | `string` | `""` | no | +| [diskspace\_threshold\_critical](#input\_diskspace\_threshold\_critical) | Disk space used in percent (critical threshold) | `string` | `"90"` | no | +| [diskspace\_threshold\_warning](#input\_diskspace\_threshold\_warning) | Disk space used in percent (warning threshold) | `string` | `"80"` | no | +| [diskspace\_time\_aggregator](#input\_diskspace\_time\_aggregator) | Monitor aggregator for SQL Elastic Pool disk space [available values: min, max or avg] | `string` | `"max"` | no | +| [diskspace\_timeframe](#input\_diskspace\_timeframe) | Monitor timeframe for SQL Elastic Pool disk space [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [dtu\_enabled](#input\_dtu\_enabled) | Flag to enable SQL Elastic Pool DTU monitor | `string` | `"true"` | no | +| [dtu\_extra\_tags](#input\_dtu\_extra\_tags) | Extra tags for SQL Elastic Pool DTU monitor | `list(string)` | `[]` | no | +| [dtu\_message](#input\_dtu\_message) | Custom message for SQL Elastic Pool DTU monitor | `string` | `""` | no | +| [dtu\_threshold\_critical](#input\_dtu\_threshold\_critical) | Amount of DTU used (critical threshold) | `string` | `"90"` | no | +| [dtu\_threshold\_warning](#input\_dtu\_threshold\_warning) | Amount of DTU used (warning threshold) | `string` | `"85"` | no | +| [dtu\_time\_aggregator](#input\_dtu\_time\_aggregator) | Monitor aggregator for SQL Elastic Pool DTU [available values: min, max or avg] | `string` | `"avg"` | no | +| [dtu\_timeframe](#input\_dtu\_timeframe) | Monitor timeframe for SQL Elastic Pool DTU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [sql\_elasticpool\_cpu\_no\_data\_timeframe](#input\_sql\_elasticpool\_cpu\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `30` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [sql\_elasticpool\_cpu\_id](#output\_sql\_elasticpool\_cpu\_id) | id for monitor sql\_elasticpool\_cpu | +| [sql\_elasticpool\_dtu\_consumption\_high\_id](#output\_sql\_elasticpool\_dtu\_consumption\_high\_id) | id for monitor sql\_elasticpool\_dtu\_consumption\_high | +| [sql\_elasticpool\_free\_space\_low\_id](#output\_sql\_elasticpool\_free\_space\_low\_id) | id for monitor sql\_elasticpool\_free\_space\_low | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure_sql_elastic_pool/](https://docs.datadoghq.com/integrations/azure_sql_elastic_pool/) + +Azure SQL Elastic Pool metrics documentation: [https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-supported#microsoftsqlserverselasticpools](https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-supported#microsoftsqlserverselasticpools) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-elasticpool/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-elasticpool/inputs.tf new file mode 100755 index 0000000..ac04bed --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-elasticpool/inputs.tf @@ -0,0 +1,174 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "sql_elasticpool_cpu_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 30 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Azure SQL Elastic Pool specific variables + +variable "cpu_enabled" { + description = "Flag to enable SQL Elastic Pool CPU monitor" + type = string + default = "true" +} + +variable "cpu_extra_tags" { + description = "Extra tags for SQL Elastic Pool CPU monitor" + type = list(string) + default = [] +} + +variable "cpu_message" { + description = "Custom message for SQL Elastic Pool CPU monitor" + type = string + default = "" +} + +variable "cpu_time_aggregator" { + description = "Monitor aggregator for SQL Elastic Pool CPU [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cpu_timeframe" { + description = "Monitor timeframe for SQL Elastic Pool CPU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "cpu_threshold_warning" { + description = "CPU usage in percent (warning threshold)" + default = "80" +} + +variable "cpu_threshold_critical" { + description = "CPU usage in percent (critical threshold)" + default = "90" +} + +variable "diskspace_enabled" { + description = "Flag to enable SQL Elastic Pool disk space monitor" + type = string + default = "true" +} + +variable "diskspace_extra_tags" { + description = "Extra tags for SQL Elastic Pool disk space monitor" + type = list(string) + default = [] +} + +variable "diskspace_message" { + description = "Custom message for SQL Elastic Pool disk space monitor" + type = string + default = "" +} + +variable "diskspace_time_aggregator" { + description = "Monitor aggregator for SQL Elastic Pool disk space [available values: min, max or avg]" + type = string + default = "max" +} + +variable "diskspace_timeframe" { + description = "Monitor timeframe for SQL Elastic Pool disk space [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "diskspace_threshold_warning" { + description = "Disk space used in percent (warning threshold)" + default = "80" +} + +variable "diskspace_threshold_critical" { + description = "Disk space used in percent (critical threshold)" + default = "90" +} + +variable "dtu_enabled" { + description = "Flag to enable SQL Elastic Pool DTU monitor" + type = string + default = "true" +} + +variable "dtu_extra_tags" { + description = "Extra tags for SQL Elastic Pool DTU monitor" + type = list(string) + default = [] +} + +variable "dtu_message" { + description = "Custom message for SQL Elastic Pool DTU monitor" + type = string + default = "" +} + +variable "dtu_time_aggregator" { + description = "Monitor aggregator for SQL Elastic Pool DTU [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "dtu_timeframe" { + description = "Monitor timeframe for SQL Elastic Pool DTU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "dtu_threshold_warning" { + description = "Amount of DTU used (warning threshold)" + default = "85" +} + +variable "dtu_threshold_critical" { + description = "Amount of DTU used (critical threshold)" + default = "90" +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-elasticpool/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-elasticpool/modules.tf new file mode 100755 index 0000000..6c5206d --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-elasticpool/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_sql-elasticpool" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-elasticpool/monitors-sql-elasticpool.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-elasticpool/monitors-sql-elasticpool.tf new file mode 100755 index 0000000..c65a1a1 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-elasticpool/monitors-sql-elasticpool.tf @@ -0,0 +1,91 @@ +resource "datadog_monitor" "sql_elasticpool_cpu" { + count = var.cpu_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] SQL Elastic Pool CPU too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cpu_message, var.message) + type = "query alert" + + query = < ${var.cpu_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.cpu_threshold_critical + warning = var.cpu_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = var.notify_no_data + no_data_timeframe = var.sql_elasticpool_cpu_no_data_timeframe + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:sql-elasticpool", "team:claranet", "created-by:terraform"], var.cpu_extra_tags) +} + +resource "datadog_monitor" "sql_elasticpool_free_space_low" { + count = var.diskspace_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] SQL Elastic Pool high disk usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.diskspace_message, var.message) + type = "query alert" + + query = < ${var.diskspace_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.diskspace_threshold_warning + critical = var.diskspace_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:sql-elasticpool", "team:claranet", "created-by:terraform"], var.diskspace_extra_tags) +} + +resource "datadog_monitor" "sql_elasticpool_dtu_consumption_high" { + count = var.dtu_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] SQL Elastic Pool DTU Consumption too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.dtu_message, var.message) + type = "query alert" + + query = < ${var.dtu_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.dtu_threshold_warning + critical = var.dtu_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:sql-elasticpool", "team:claranet", "created-by:terraform"], var.dtu_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-elasticpool/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-elasticpool/outputs.tf new file mode 100755 index 0000000..7c7d733 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-elasticpool/outputs.tf @@ -0,0 +1,15 @@ +output "sql_elasticpool_cpu_id" { + description = "id for monitor sql_elasticpool_cpu" + value = datadog_monitor.sql_elasticpool_cpu.*.id +} + +output "sql_elasticpool_dtu_consumption_high_id" { + description = "id for monitor sql_elasticpool_dtu_consumption_high" + value = datadog_monitor.sql_elasticpool_dtu_consumption_high.*.id +} + +output "sql_elasticpool_free_space_low_id" { + description = "id for monitor sql_elasticpool_free_space_low" + value = datadog_monitor.sql_elasticpool_free_space_low.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-elasticpool/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-elasticpool/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/sql-elasticpool/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/storage/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/storage/README.md new file mode 100755 index 0000000..9a27848 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/storage/README.md @@ -0,0 +1,249 @@ +# CLOUD AZURE STORAGE DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-storage" { + source = "claranet/monitors/datadog//cloud/azure/storage" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Azure Blob Storage too many authorization errors +- Azure Blob Storage too many client_other errors +- Azure Blob Storage too many network errors +- Azure Blob Storage too many server_other errors +- Azure Blob Storage too many throttling errors +- Azure Blob Storage too many timeout errors +- Azure File Storage too many authorization errors +- Azure File Storage too many client_other errors +- Azure File Storage too many network errors +- Azure File Storage too many server_other errors +- Azure File Storage too many throttling errors +- Azure File Storage too many timeout errors +- Azure Queue Storage too many authorization errors +- Azure Queue Storage too many client_other errors +- Azure Queue Storage too many network errors +- Azure Queue Storage too many server_other errors +- Azure Queue Storage too many throttling errors +- Azure Queue Storage too many timeout errors +- Azure Storage Blob service too few successful requests +- Azure Storage Blob service too high end to end latency +- Azure Storage File service too few successful requests +- Azure Storage File service too high end to end latency +- Azure Storage is down +- Azure Storage Queue service too few successful requests +- Azure Storage Queue service too high end to end latency +- Azure Storage Table service too few successful requests +- Azure Storage Table service too high end to end latency +- Azure Table Storage too many authorization errors +- Azure Table Storage too many client_other errors +- Azure Table Storage too many network errors +- Azure Table Storage too many server_other errors +- Azure Table Storage too many throttling errors +- Azure Table Storage too many timeout errors + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | +| [filter-tags-authorization-error](#module\_filter-tags-authorization-error) | ../../../common/filter-tags | n/a | +| [filter-tags-blob](#module\_filter-tags-blob) | ../../../common/filter-tags | n/a | +| [filter-tags-client-other-error](#module\_filter-tags-client-other-error) | ../../../common/filter-tags | n/a | +| [filter-tags-client-other-error-blob](#module\_filter-tags-client-other-error-blob) | ../../../common/filter-tags | n/a | +| [filter-tags-network-error](#module\_filter-tags-network-error) | ../../../common/filter-tags | n/a | +| [filter-tags-server-other-error](#module\_filter-tags-server-other-error) | ../../../common/filter-tags | n/a | +| [filter-tags-success](#module\_filter-tags-success) | ../../../common/filter-tags | n/a | +| [filter-tags-success-blob](#module\_filter-tags-success-blob) | ../../../common/filter-tags | n/a | +| [filter-tags-throttling-error](#module\_filter-tags-throttling-error) | ../../../common/filter-tags | n/a | +| [filter-tags-timeout-error](#module\_filter-tags-timeout-error) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.blob_authorization_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.blob_client_other_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.blob_network_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.blob_server_other_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.blob_throttling_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.blob_timeout_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.blobservices_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.blobservices_requests_error](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.file_authorization_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.file_client_other_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.file_network_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.file_server_other_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.file_throttling_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.file_timeout_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.fileservices_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.fileservices_requests_error](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.queue_authorization_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.queue_client_other_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.queue_network_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.queue_server_other_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.queue_throttling_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.queue_timeout_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.queueservices_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.queueservices_requests_error](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.storage_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.table_authorization_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.table_client_other_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.table_network_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.table_server_other_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.table_throttling_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.table_timeout_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.tableservices_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.tableservices_requests_error](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [authorization\_error\_requests\_enabled](#input\_authorization\_error\_requests\_enabled) | Flag to enable Storage authorization errors monitor | `string` | `"true"` | no | +| [authorization\_error\_requests\_extra\_tags](#input\_authorization\_error\_requests\_extra\_tags) | Extra tags for Storage authorization errors monitor | `list(string)` | `[]` | no | +| [authorization\_error\_requests\_message](#input\_authorization\_error\_requests\_message) | Custom message for Storage authorization errors monitor | `string` | `""` | no | +| [authorization\_error\_requests\_threshold\_critical](#input\_authorization\_error\_requests\_threshold\_critical) | Maximum acceptable percent of authorization error requests for a storage | `number` | `90` | no | +| [authorization\_error\_requests\_threshold\_warning](#input\_authorization\_error\_requests\_threshold\_warning) | Warning regarding acceptable percent of authorization error requests for a storage | `number` | `50` | no | +| [authorization\_error\_requests\_time\_aggregator](#input\_authorization\_error\_requests\_time\_aggregator) | Monitor aggregator for Storage authorization errors [available values: min, max or avg] | `string` | `"min"` | no | +| [authorization\_error\_requests\_timeframe](#input\_authorization\_error\_requests\_timeframe) | Monitor timeframe for Storage authorization errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [availability\_enabled](#input\_availability\_enabled) | Flag to enable Storage availability monitor | `string` | `"true"` | no | +| [availability\_extra\_tags](#input\_availability\_extra\_tags) | Extra tags for Storage availability monitor | `list(string)` | `[]` | no | +| [availability\_message](#input\_availability\_message) | Custom message for Storage availability monitor | `string` | `""` | no | +| [availability\_threshold\_critical](#input\_availability\_threshold\_critical) | Minimum acceptable percent of availability for a storage | `number` | `50` | no | +| [availability\_threshold\_warning](#input\_availability\_threshold\_warning) | Warning regarding acceptable percent of availability for a storage | `number` | `90` | no | +| [availability\_time\_aggregator](#input\_availability\_time\_aggregator) | Monitor aggregator for Storage availability [available values: min, max or avg] | `string` | `"max"` | no | +| [availability\_timeframe](#input\_availability\_timeframe) | Monitor timeframe for Storage availability [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [client\_other\_error\_requests\_enabled](#input\_client\_other\_error\_requests\_enabled) | Flag to enable Storage other errors monitor | `string` | `"true"` | no | +| [client\_other\_error\_requests\_extra\_tags](#input\_client\_other\_error\_requests\_extra\_tags) | Extra tags for Storage other errors monitor | `list(string)` | `[]` | no | +| [client\_other\_error\_requests\_message](#input\_client\_other\_error\_requests\_message) | Custom message for Storage other errors monitor | `string` | `""` | no | +| [client\_other\_error\_requests\_threshold\_critical](#input\_client\_other\_error\_requests\_threshold\_critical) | Maximum acceptable percent of client other error requests for a storage | `number` | `90` | no | +| [client\_other\_error\_requests\_threshold\_warning](#input\_client\_other\_error\_requests\_threshold\_warning) | Warning regarding acceptable percent of client other error requests for a storage | `number` | `50` | no | +| [client\_other\_error\_requests\_time\_aggregator](#input\_client\_other\_error\_requests\_time\_aggregator) | Monitor aggregator for Storage other errors [available values: min, max or avg] | `string` | `"min"` | no | +| [client\_other\_error\_requests\_timeframe](#input\_client\_other\_error\_requests\_timeframe) | Monitor timeframe for Storage other errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [latency\_enabled](#input\_latency\_enabled) | Flag to enable Storage latency monitor | `string` | `"true"` | no | +| [latency\_extra\_tags](#input\_latency\_extra\_tags) | Extra tags for Storage latency monitor | `list(string)` | `[]` | no | +| [latency\_message](#input\_latency\_message) | Custom message for Storage latency monitor | `string` | `""` | no | +| [latency\_threshold\_critical](#input\_latency\_threshold\_critical) | Maximum acceptable end to end latency (ms) for a storage | `number` | `2000` | no | +| [latency\_threshold\_warning](#input\_latency\_threshold\_warning) | Warning regarding acceptable end to end latency (ms) for a storage | `number` | `1000` | no | +| [latency\_time\_aggregator](#input\_latency\_time\_aggregator) | Monitor aggregator for Storage latency [available values: min, max or avg] | `string` | `"min"` | no | +| [latency\_timeframe](#input\_latency\_timeframe) | Monitor timeframe for Storage latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when a Redis monitor is triggered | `any` | n/a | yes | +| [network\_error\_requests\_enabled](#input\_network\_error\_requests\_enabled) | Flag to enable Storage network errors monitor | `string` | `"true"` | no | +| [network\_error\_requests\_extra\_tags](#input\_network\_error\_requests\_extra\_tags) | Extra tags for Storage network errors monitor | `list(string)` | `[]` | no | +| [network\_error\_requests\_message](#input\_network\_error\_requests\_message) | Custom message for Storage network errors monitor | `string` | `""` | no | +| [network\_error\_requests\_threshold\_critical](#input\_network\_error\_requests\_threshold\_critical) | Maximum acceptable percent of network error requests for a storage | `number` | `90` | no | +| [network\_error\_requests\_threshold\_warning](#input\_network\_error\_requests\_threshold\_warning) | Warning regarding acceptable percent of network error requests for a storage | `number` | `50` | no | +| [network\_error\_requests\_time\_aggregator](#input\_network\_error\_requests\_time\_aggregator) | Monitor aggregator for Storage network errors [available values: min, max or avg] | `string` | `"min"` | no | +| [network\_error\_requests\_timeframe](#input\_network\_error\_requests\_timeframe) | Monitor timeframe for Storage network errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [server\_other\_error\_requests\_enabled](#input\_server\_other\_error\_requests\_enabled) | Flag to enable Storage server other errors monitor | `string` | `"true"` | no | +| [server\_other\_error\_requests\_extra\_tags](#input\_server\_other\_error\_requests\_extra\_tags) | Extra tags for Storage server other errors monitor | `list(string)` | `[]` | no | +| [server\_other\_error\_requests\_message](#input\_server\_other\_error\_requests\_message) | Custom message for Storage server other errors monitor | `string` | `""` | no | +| [server\_other\_error\_requests\_threshold\_critical](#input\_server\_other\_error\_requests\_threshold\_critical) | Maximum acceptable percent of server other error requests for a storage | `number` | `90` | no | +| [server\_other\_error\_requests\_threshold\_warning](#input\_server\_other\_error\_requests\_threshold\_warning) | Warning regarding acceptable percent of server other error requests for a storage | `number` | `50` | no | +| [server\_other\_error\_requests\_time\_aggregator](#input\_server\_other\_error\_requests\_time\_aggregator) | Monitor aggregator for Storage other errors [available values: min, max or avg] | `string` | `"min"` | no | +| [server\_other\_error\_requests\_timeframe](#input\_server\_other\_error\_requests\_timeframe) | Monitor timeframe for Storage server other errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable App Services status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for App Services status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for storage Services status monitor | `string` | `""` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for Storage Services status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for Storage Services status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [storage\_status\_no\_data\_timeframe](#input\_storage\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [successful\_requests\_enabled](#input\_successful\_requests\_enabled) | Flag to enable Storage sucessful requests monitor | `string` | `"true"` | no | +| [successful\_requests\_extra\_tags](#input\_successful\_requests\_extra\_tags) | Extra tags for Storage sucessful requests monitor | `list(string)` | `[]` | no | +| [successful\_requests\_message](#input\_successful\_requests\_message) | Custom message for Storage sucessful requests monitor | `string` | `""` | no | +| [successful\_requests\_time\_aggregator](#input\_successful\_requests\_time\_aggregator) | Monitor aggregator for Storage sucessful requests [available values: min, max or avg] | `string` | `"max"` | no | +| [successful\_requests\_timeframe](#input\_successful\_requests\_timeframe) | Monitor timeframe for Storage sucessful requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [successful\_storage\_requests\_threshold\_critical](#input\_successful\_storage\_requests\_threshold\_critical) | Minimum acceptable percent of successful requests for a storage | `number` | `90` | no | +| [successful\_storage\_requests\_threshold\_warning](#input\_successful\_storage\_requests\_threshold\_warning) | Warning regarding acceptable percent of successful requests for a storage | `number` | `70` | no | +| [throttling\_error\_requests\_enabled](#input\_throttling\_error\_requests\_enabled) | Flag to enable Storage throttling error monitor | `string` | `"true"` | no | +| [throttling\_error\_requests\_extra\_tags](#input\_throttling\_error\_requests\_extra\_tags) | Extra tags for Storage throttling error monitor | `list(string)` | `[]` | no | +| [throttling\_error\_requests\_message](#input\_throttling\_error\_requests\_message) | Custom message for Storage throttling error monitor | `string` | `""` | no | +| [throttling\_error\_requests\_threshold\_critical](#input\_throttling\_error\_requests\_threshold\_critical) | Maximum acceptable percent of throttling error requests for a storage | `number` | `90` | no | +| [throttling\_error\_requests\_threshold\_warning](#input\_throttling\_error\_requests\_threshold\_warning) | Warning regarding acceptable percent of throttling error requests for a storage | `number` | `50` | no | +| [throttling\_error\_requests\_time\_aggregator](#input\_throttling\_error\_requests\_time\_aggregator) | Monitor aggregator for Storage throttling errors [available values: min, max or avg] | `string` | `"min"` | no | +| [throttling\_error\_requests\_timeframe](#input\_throttling\_error\_requests\_timeframe) | Monitor timeframe for Storage throttling errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [timeout\_error\_requests\_enabled](#input\_timeout\_error\_requests\_enabled) | Flag to enable Storage timeout monitor | `string` | `"true"` | no | +| [timeout\_error\_requests\_extra\_tags](#input\_timeout\_error\_requests\_extra\_tags) | Extra tags for Storage timeout monitor | `list(string)` | `[]` | no | +| [timeout\_error\_requests\_message](#input\_timeout\_error\_requests\_message) | Custom message for Storage timeout monitor | `string` | `""` | no | +| [timeout\_error\_requests\_threshold\_critical](#input\_timeout\_error\_requests\_threshold\_critical) | Maximum acceptable percent of timeout error requests for a storage | `number` | `90` | no | +| [timeout\_error\_requests\_threshold\_warning](#input\_timeout\_error\_requests\_threshold\_warning) | Warning regarding acceptable percent of timeout error requests for a storage | `number` | `50` | no | +| [timeout\_error\_requests\_time\_aggregator](#input\_timeout\_error\_requests\_time\_aggregator) | Monitor aggregator for Storage timeout [available values: min, max or avg] | `string` | `"min"` | no | +| [timeout\_error\_requests\_timeframe](#input\_timeout\_error\_requests\_timeframe) | Monitor timeframe for Storage timeout [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [blob\_authorization\_error\_requests\_id](#output\_blob\_authorization\_error\_requests\_id) | id for monitor blob\_authorization\_error\_requests | +| [blob\_client\_other\_error\_requests\_id](#output\_blob\_client\_other\_error\_requests\_id) | id for monitor blob\_client\_other\_error\_requests | +| [blob\_network\_error\_requests\_id](#output\_blob\_network\_error\_requests\_id) | id for monitor blob\_network\_error\_requests | +| [blob\_server\_other\_error\_requests\_id](#output\_blob\_server\_other\_error\_requests\_id) | id for monitor blob\_server\_other\_error\_requests | +| [blob\_throttling\_error\_requests\_id](#output\_blob\_throttling\_error\_requests\_id) | id for monitor blob\_throttling\_error\_requests | +| [blob\_timeout\_error\_requests\_id](#output\_blob\_timeout\_error\_requests\_id) | id for monitor blob\_timeout\_error\_requests | +| [blobservices\_latency\_id](#output\_blobservices\_latency\_id) | id for monitor blobservices\_latency | +| [blobservices\_requests\_error\_id](#output\_blobservices\_requests\_error\_id) | id for monitor blobservices\_requests\_error | +| [file\_authorization\_error\_requests\_id](#output\_file\_authorization\_error\_requests\_id) | id for monitor file\_authorization\_error\_requests | +| [file\_client\_other\_error\_requests\_id](#output\_file\_client\_other\_error\_requests\_id) | id for monitor file\_client\_other\_error\_requests | +| [file\_network\_error\_requests\_id](#output\_file\_network\_error\_requests\_id) | id for monitor file\_network\_error\_requests | +| [file\_server\_other\_error\_requests\_id](#output\_file\_server\_other\_error\_requests\_id) | id for monitor file\_server\_other\_error\_requests | +| [file\_throttling\_error\_requests\_id](#output\_file\_throttling\_error\_requests\_id) | id for monitor file\_throttling\_error\_requests | +| [file\_timeout\_error\_requests\_id](#output\_file\_timeout\_error\_requests\_id) | id for monitor file\_timeout\_error\_requests | +| [fileservices\_latency\_id](#output\_fileservices\_latency\_id) | id for monitor fileservices\_latency | +| [fileservices\_requests\_error\_id](#output\_fileservices\_requests\_error\_id) | id for monitor fileservices\_requests\_error | +| [queue\_authorization\_error\_requests\_id](#output\_queue\_authorization\_error\_requests\_id) | id for monitor queue\_authorization\_error\_requests | +| [queue\_client\_other\_error\_requests\_id](#output\_queue\_client\_other\_error\_requests\_id) | id for monitor queue\_client\_other\_error\_requests | +| [queue\_network\_error\_requests\_id](#output\_queue\_network\_error\_requests\_id) | id for monitor queue\_network\_error\_requests | +| [queue\_server\_other\_error\_requests\_id](#output\_queue\_server\_other\_error\_requests\_id) | id for monitor queue\_server\_other\_error\_requests | +| [queue\_throttling\_error\_requests\_id](#output\_queue\_throttling\_error\_requests\_id) | id for monitor queue\_throttling\_error\_requests | +| [queue\_timeout\_error\_requests\_id](#output\_queue\_timeout\_error\_requests\_id) | id for monitor queue\_timeout\_error\_requests | +| [queueservices\_latency\_id](#output\_queueservices\_latency\_id) | id for monitor queueservices\_latency | +| [queueservices\_requests\_error\_id](#output\_queueservices\_requests\_error\_id) | id for monitor queueservices\_requests\_error | +| [storage\_status\_id](#output\_storage\_status\_id) | id for monitor storage\_status | +| [table\_authorization\_error\_requests\_id](#output\_table\_authorization\_error\_requests\_id) | id for monitor table\_authorization\_error\_requests | +| [table\_client\_other\_error\_requests\_id](#output\_table\_client\_other\_error\_requests\_id) | id for monitor table\_client\_other\_error\_requests | +| [table\_network\_error\_requests\_id](#output\_table\_network\_error\_requests\_id) | id for monitor table\_network\_error\_requests | +| [table\_server\_other\_error\_requests\_id](#output\_table\_server\_other\_error\_requests\_id) | id for monitor table\_server\_other\_error\_requests | +| [table\_throttling\_error\_requests\_id](#output\_table\_throttling\_error\_requests\_id) | id for monitor table\_throttling\_error\_requests | +| [table\_timeout\_error\_requests\_id](#output\_table\_timeout\_error\_requests\_id) | id for monitor table\_timeout\_error\_requests | +| [tableservices\_latency\_id](#output\_tableservices\_latency\_id) | id for monitor tableservices\_latency | +| [tableservices\_requests\_error\_id](#output\_tableservices\_requests\_error\_id) | id for monitor tableservices\_requests\_error | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure_storage/](https://docs.datadoghq.com/integrations/azure_storage/) + +DataDog blog: [https://www.datadoghq.com/blog/monitor-azure-storage-datadog/](https://www.datadoghq.com/blog/monitor-azure-storage-datadog/) + +Azure Storage metrics documentation: [https://docs.microsoft.com/en-us/azure/storage/common/storage-monitor-storage-account](https://docs.microsoft.com/en-us/azure/storage/common/storage-monitor-storage-account) + +Azure Storage metrics detailed documentation [https://docs.microsoft.com/en-us/rest/api/storageservices/storage-analytics-metrics-table-schema](https://docs.microsoft.com/en-us/rest/api/storageservices/storage-analytics-metrics-table-schema) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/storage/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/storage/inputs.tf new file mode 100755 index 0000000..9478a7f --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/storage/inputs.tf @@ -0,0 +1,442 @@ +# Global Terraform +variable "environment" { + description = "Architecture environment" + type = string +} + +# Global DataDog +variable "message" { + description = "Message sent when a Redis monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "storage_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Azure Storage specific variables +variable "availability_enabled" { + description = "Flag to enable Storage availability monitor" + type = string + default = "true" +} + +variable "availability_extra_tags" { + description = "Extra tags for Storage availability monitor" + type = list(string) + default = [] +} + +variable "availability_message" { + description = "Custom message for Storage availability monitor" + type = string + default = "" +} + +variable "availability_time_aggregator" { + description = "Monitor aggregator for Storage availability [available values: min, max or avg]" + type = string + default = "max" +} + +variable "availability_timeframe" { + description = "Monitor timeframe for Storage availability [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "availability_threshold_critical" { + description = "Minimum acceptable percent of availability for a storage" + default = 50 +} + +variable "availability_threshold_warning" { + description = "Warning regarding acceptable percent of availability for a storage" + default = 90 +} + +variable "successful_requests_enabled" { + description = "Flag to enable Storage sucessful requests monitor" + type = string + default = "true" +} + +variable "successful_requests_extra_tags" { + description = "Extra tags for Storage sucessful requests monitor" + type = list(string) + default = [] +} + +variable "successful_requests_message" { + description = "Custom message for Storage sucessful requests monitor" + type = string + default = "" +} + +variable "successful_requests_time_aggregator" { + description = "Monitor aggregator for Storage sucessful requests [available values: min, max or avg]" + type = string + default = "max" +} + +variable "successful_requests_timeframe" { + description = "Monitor timeframe for Storage sucessful requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "successful_storage_requests_threshold_critical" { + description = "Minimum acceptable percent of successful requests for a storage" + default = 90 +} + +variable "successful_storage_requests_threshold_warning" { + description = "Warning regarding acceptable percent of successful requests for a storage" + default = 70 +} + +variable "latency_enabled" { + description = "Flag to enable Storage latency monitor" + type = string + default = "true" +} + +variable "latency_extra_tags" { + description = "Extra tags for Storage latency monitor" + type = list(string) + default = [] +} + +variable "latency_message" { + description = "Custom message for Storage latency monitor" + type = string + default = "" +} + +variable "latency_time_aggregator" { + description = "Monitor aggregator for Storage latency [available values: min, max or avg]" + type = string + default = "min" +} + +variable "latency_timeframe" { + description = "Monitor timeframe for Storage latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "latency_threshold_critical" { + description = "Maximum acceptable end to end latency (ms) for a storage" + default = 2000 +} + +variable "latency_threshold_warning" { + description = "Warning regarding acceptable end to end latency (ms) for a storage" + default = 1000 +} + +variable "timeout_error_requests_enabled" { + description = "Flag to enable Storage timeout monitor" + type = string + default = "true" +} + +variable "timeout_error_requests_extra_tags" { + description = "Extra tags for Storage timeout monitor" + type = list(string) + default = [] +} + +variable "timeout_error_requests_message" { + description = "Custom message for Storage timeout monitor" + type = string + default = "" +} + +variable "timeout_error_requests_time_aggregator" { + description = "Monitor aggregator for Storage timeout [available values: min, max or avg]" + type = string + default = "min" +} + +variable "timeout_error_requests_timeframe" { + description = "Monitor timeframe for Storage timeout [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "timeout_error_requests_threshold_critical" { + description = "Maximum acceptable percent of timeout error requests for a storage" + default = 90 +} + +variable "timeout_error_requests_threshold_warning" { + description = "Warning regarding acceptable percent of timeout error requests for a storage" + default = 50 +} + +variable "network_error_requests_enabled" { + description = "Flag to enable Storage network errors monitor" + type = string + default = "true" +} + +variable "network_error_requests_extra_tags" { + description = "Extra tags for Storage network errors monitor" + type = list(string) + default = [] +} + +variable "network_error_requests_message" { + description = "Custom message for Storage network errors monitor" + type = string + default = "" +} + +variable "network_error_requests_time_aggregator" { + description = "Monitor aggregator for Storage network errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "network_error_requests_timeframe" { + description = "Monitor timeframe for Storage network errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "network_error_requests_threshold_critical" { + description = "Maximum acceptable percent of network error requests for a storage" + default = 90 +} + +variable "network_error_requests_threshold_warning" { + description = "Warning regarding acceptable percent of network error requests for a storage" + default = 50 +} + +variable "throttling_error_requests_enabled" { + description = "Flag to enable Storage throttling error monitor" + type = string + default = "true" +} + +variable "throttling_error_requests_extra_tags" { + description = "Extra tags for Storage throttling error monitor" + type = list(string) + default = [] +} + +variable "throttling_error_requests_message" { + description = "Custom message for Storage throttling error monitor" + type = string + default = "" +} + +variable "throttling_error_requests_time_aggregator" { + description = "Monitor aggregator for Storage throttling errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "throttling_error_requests_timeframe" { + description = "Monitor timeframe for Storage throttling errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "throttling_error_requests_threshold_critical" { + description = "Maximum acceptable percent of throttling error requests for a storage" + default = 90 +} + +variable "throttling_error_requests_threshold_warning" { + description = "Warning regarding acceptable percent of throttling error requests for a storage" + default = 50 +} + +variable "server_other_error_requests_enabled" { + description = "Flag to enable Storage server other errors monitor" + type = string + default = "true" +} + +variable "server_other_error_requests_extra_tags" { + description = "Extra tags for Storage server other errors monitor" + type = list(string) + default = [] +} + +variable "server_other_error_requests_message" { + description = "Custom message for Storage server other errors monitor" + type = string + default = "" +} + +variable "server_other_error_requests_time_aggregator" { + description = "Monitor aggregator for Storage other errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "server_other_error_requests_timeframe" { + description = "Monitor timeframe for Storage server other errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "server_other_error_requests_threshold_critical" { + description = "Maximum acceptable percent of server other error requests for a storage" + default = 90 +} + +variable "server_other_error_requests_threshold_warning" { + description = "Warning regarding acceptable percent of server other error requests for a storage" + default = 50 +} + +variable "client_other_error_requests_enabled" { + description = "Flag to enable Storage other errors monitor" + type = string + default = "true" +} + +variable "client_other_error_requests_extra_tags" { + description = "Extra tags for Storage other errors monitor" + type = list(string) + default = [] +} + +variable "client_other_error_requests_message" { + description = "Custom message for Storage other errors monitor" + type = string + default = "" +} + +variable "client_other_error_requests_time_aggregator" { + description = "Monitor aggregator for Storage other errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "client_other_error_requests_timeframe" { + description = "Monitor timeframe for Storage other errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "client_other_error_requests_threshold_critical" { + description = "Maximum acceptable percent of client other error requests for a storage" + default = 90 +} + +variable "client_other_error_requests_threshold_warning" { + description = "Warning regarding acceptable percent of client other error requests for a storage" + default = 50 +} + +variable "authorization_error_requests_enabled" { + description = "Flag to enable Storage authorization errors monitor" + type = string + default = "true" +} + +variable "authorization_error_requests_extra_tags" { + description = "Extra tags for Storage authorization errors monitor" + type = list(string) + default = [] +} + +variable "authorization_error_requests_message" { + description = "Custom message for Storage authorization errors monitor" + type = string + default = "" +} + +variable "authorization_error_requests_time_aggregator" { + description = "Monitor aggregator for Storage authorization errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "authorization_error_requests_timeframe" { + description = "Monitor timeframe for Storage authorization errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "authorization_error_requests_threshold_critical" { + description = "Maximum acceptable percent of authorization error requests for a storage" + default = 90 +} + +variable "authorization_error_requests_threshold_warning" { + description = "Warning regarding acceptable percent of authorization error requests for a storage" + default = 50 +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for Storage Services status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for Storage Services status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "status_enabled" { + description = "Flag to enable App Services status monitor" + type = string + default = "true" +} + +variable "status_message" { + description = "Custom message for storage Services status monitor" + type = string + default = "" +} + +variable "status_extra_tags" { + description = "Extra tags for App Services status monitor" + type = list(string) + default = [] +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/storage/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/storage/modules.tf new file mode 100755 index 0000000..db573ae --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/storage/modules.tf @@ -0,0 +1,123 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_storage" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = [] +} + +module "filter-tags-blob" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_storage" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = [] + extra_tags_excluded = ["apiname:getblobproperties", "apiname:createcontainer"] +} + +module "filter-tags-success" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_storage" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["responsetype:success"] +} + +module "filter-tags-success-blob" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_storage" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["responsetype:success"] + extra_tags_excluded = ["apiname:getblobproperties", "apiname:createcontainer"] +} + +module "filter-tags-timeout-error" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_storage" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["responsetype:servertimeouterror"] +} + +module "filter-tags-network-error" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_storage" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["responsetype:networkerror"] +} + +module "filter-tags-throttling-error" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_storage" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["responsetype:serverbusyerror"] +} + +module "filter-tags-server-other-error" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_storage" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["responsetype:serverothererror"] +} + +module "filter-tags-client-other-error" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_storage" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["responsetype:clientothererror"] +} + +module "filter-tags-client-other-error-blob" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_storage" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["responsetype:clientothererror"] + extra_tags_excluded = ["apiname:getblobproperties", "apiname:createcontainer"] +} + +module "filter-tags-authorization-error" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_storage" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["responsetype:authorizationerror"] +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/storage/monitors-azure-storage.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/storage/monitors-azure-storage.tf new file mode 100755 index 0000000..918ec7c --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/storage/monitors-azure-storage.tf @@ -0,0 +1,1044 @@ +resource "datadog_monitor" "storage_status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Storage is down" + message = coalesce(var.status_message, var.message) + + query = < ${var.successful_storage_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.successful_storage_requests_threshold_critical + warning = var.successful_storage_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.successful_requests_extra_tags) +} + +resource "datadog_monitor" "fileservices_requests_error" { + count = var.successful_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Storage File service too few successful requests {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.successful_requests_message, var.message) + query = < ${var.successful_storage_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.successful_storage_requests_threshold_critical + warning = var.successful_storage_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.successful_requests_extra_tags) +} + +resource "datadog_monitor" "queueservices_requests_error" { + count = var.successful_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Storage Queue service too few successful requests {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.successful_requests_message, var.message) + + query = < ${var.successful_storage_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.successful_storage_requests_threshold_critical + warning = var.successful_storage_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.successful_requests_extra_tags) +} + +resource "datadog_monitor" "tableservices_requests_error" { + count = var.successful_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Storage Table service too few successful requests {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.successful_requests_message, var.message) + + query = < ${var.successful_storage_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.successful_storage_requests_threshold_critical + warning = var.successful_storage_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.successful_requests_extra_tags) +} + +resource "datadog_monitor" "blobservices_latency" { + count = var.latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Storage Blob service too high end to end latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.latency_message, var.message) + + query = < ${var.latency_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.latency_threshold_critical + warning = var.latency_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.latency_extra_tags) +} + +resource "datadog_monitor" "fileservices_latency" { + count = var.latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Storage File service too high end to end latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.latency_message, var.message) + + query = < ${var.latency_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.latency_threshold_critical + warning = var.latency_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.latency_extra_tags) +} + +resource "datadog_monitor" "queueservices_latency" { + count = var.latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Storage Queue service too high end to end latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.latency_message, var.message) + + query = < ${var.latency_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.latency_threshold_critical + warning = var.latency_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.latency_extra_tags) +} + +resource "datadog_monitor" "tableservices_latency" { + count = var.latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Storage Table service too high end to end latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.latency_message, var.message) + + query = < ${var.latency_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.latency_threshold_critical + warning = var.latency_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.latency_extra_tags) +} + +resource "datadog_monitor" "blob_timeout_error_requests" { + count = var.timeout_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Blob Storage too many timeout errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.timeout_error_requests_message, var.message) + + query = < ${var.timeout_error_requests_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.timeout_error_requests_threshold_critical + warning = var.timeout_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.timeout_error_requests_extra_tags) +} + +resource "datadog_monitor" "file_timeout_error_requests" { + count = var.timeout_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure File Storage too many timeout errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.timeout_error_requests_message, var.message) + + query = < ${var.timeout_error_requests_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.timeout_error_requests_threshold_critical + warning = var.timeout_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.timeout_error_requests_extra_tags) +} + +resource "datadog_monitor" "queue_timeout_error_requests" { + count = var.timeout_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Queue Storage too many timeout errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.timeout_error_requests_message, var.message) + + query = < ${var.timeout_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.timeout_error_requests_threshold_critical + warning = var.timeout_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.timeout_error_requests_extra_tags) +} + +resource "datadog_monitor" "table_timeout_error_requests" { + count = var.timeout_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Table Storage too many timeout errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.timeout_error_requests_message, var.message) + + query = < ${var.timeout_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.timeout_error_requests_threshold_critical + warning = var.timeout_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.timeout_error_requests_extra_tags) +} + +resource "datadog_monitor" "blob_network_error_requests" { + count = var.network_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Blob Storage too many network errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.network_error_requests_message, var.message) + + query = < ${var.network_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.network_error_requests_threshold_critical + warning = var.network_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.network_error_requests_extra_tags) +} + +resource "datadog_monitor" "file_network_error_requests" { + count = var.network_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure File Storage too many network errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.network_error_requests_message, var.message) + + query = < ${var.network_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.network_error_requests_threshold_critical + warning = var.network_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.network_error_requests_extra_tags) +} + +resource "datadog_monitor" "queue_network_error_requests" { + count = var.network_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Queue Storage too many network errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.network_error_requests_message, var.message) + + query = < ${var.network_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.network_error_requests_threshold_critical + warning = var.network_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.network_error_requests_extra_tags) +} + +resource "datadog_monitor" "table_network_error_requests" { + count = var.network_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Table Storage too many network errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.network_error_requests_message, var.message) + + query = < ${var.network_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.network_error_requests_threshold_critical + warning = var.network_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.network_error_requests_extra_tags) +} + +resource "datadog_monitor" "blob_throttling_error_requests" { + count = var.throttling_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Blob Storage too many throttling errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.throttling_error_requests_message, var.message) + + query = < ${var.throttling_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.throttling_error_requests_threshold_critical + warning = var.throttling_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.throttling_error_requests_extra_tags) +} + +resource "datadog_monitor" "file_throttling_error_requests" { + count = var.throttling_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure File Storage too many throttling errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.throttling_error_requests_message, var.message) + + query = < ${var.throttling_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.throttling_error_requests_threshold_critical + warning = var.throttling_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.throttling_error_requests_extra_tags) +} + +resource "datadog_monitor" "queue_throttling_error_requests" { + count = var.throttling_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Queue Storage too many throttling errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.throttling_error_requests_message, var.message) + + query = < ${var.throttling_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.throttling_error_requests_threshold_critical + warning = var.throttling_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.throttling_error_requests_extra_tags) +} + +resource "datadog_monitor" "table_throttling_error_requests" { + count = var.throttling_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Table Storage too many throttling errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.throttling_error_requests_message, var.message) + + query = < ${var.throttling_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.throttling_error_requests_threshold_critical + warning = var.throttling_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.throttling_error_requests_extra_tags) +} + +resource "datadog_monitor" "blob_server_other_error_requests" { + count = var.server_other_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Blob Storage too many server_other errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.server_other_error_requests_message, var.message) + + query = < ${var.server_other_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.server_other_error_requests_threshold_critical + warning = var.server_other_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.server_other_error_requests_extra_tags) +} + +resource "datadog_monitor" "file_server_other_error_requests" { + count = var.server_other_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure File Storage too many server_other errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.server_other_error_requests_message, var.message) + + query = < ${var.server_other_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.server_other_error_requests_threshold_critical + warning = var.server_other_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.server_other_error_requests_extra_tags) +} + +resource "datadog_monitor" "queue_server_other_error_requests" { + count = var.server_other_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Queue Storage too many server_other errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.server_other_error_requests_message, var.message) + + query = < ${var.server_other_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.server_other_error_requests_threshold_critical + warning = var.server_other_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.server_other_error_requests_extra_tags) +} + +resource "datadog_monitor" "table_server_other_error_requests" { + count = var.server_other_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Table Storage too many server_other errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.server_other_error_requests_message, var.message) + + query = < ${var.server_other_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.server_other_error_requests_threshold_critical + warning = var.server_other_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.server_other_error_requests_extra_tags) +} + +resource "datadog_monitor" "blob_client_other_error_requests" { + count = var.client_other_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Blob Storage too many client_other errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.client_other_error_requests_message, var.message) + query = < ${var.client_other_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.client_other_error_requests_threshold_critical + warning = var.client_other_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.client_other_error_requests_extra_tags) +} + +resource "datadog_monitor" "file_client_other_error_requests" { + count = var.client_other_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure File Storage too many client_other errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.client_other_error_requests_message, var.message) + + query = < ${var.client_other_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.client_other_error_requests_threshold_critical + warning = var.client_other_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.client_other_error_requests_extra_tags) +} + +resource "datadog_monitor" "queue_client_other_error_requests" { + count = var.client_other_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Queue Storage too many client_other errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.client_other_error_requests_message, var.message) + + query = < ${var.client_other_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.client_other_error_requests_threshold_critical + warning = var.client_other_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.client_other_error_requests_extra_tags) +} + +resource "datadog_monitor" "table_client_other_error_requests" { + count = var.client_other_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Table Storage too many client_other errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.client_other_error_requests_message, var.message) + + query = < ${var.client_other_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.client_other_error_requests_threshold_critical + warning = var.client_other_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.client_other_error_requests_extra_tags) +} + +resource "datadog_monitor" "blob_authorization_error_requests" { + count = var.authorization_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Blob Storage too many authorization errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.authorization_error_requests_message, var.message) + + query = < ${var.authorization_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.authorization_error_requests_threshold_critical + warning = var.authorization_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.authorization_error_requests_extra_tags) +} + +resource "datadog_monitor" "file_authorization_error_requests" { + count = var.authorization_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure File Storage too many authorization errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.authorization_error_requests_message, var.message) + + query = < ${var.authorization_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.authorization_error_requests_threshold_critical + warning = var.authorization_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.authorization_error_requests_extra_tags) +} + +resource "datadog_monitor" "queue_authorization_error_requests" { + count = var.authorization_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Queue Storage too many authorization errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.authorization_error_requests_message, var.message) + + query = < ${var.authorization_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.authorization_error_requests_threshold_critical + warning = var.authorization_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.authorization_error_requests_extra_tags) +} + +resource "datadog_monitor" "table_authorization_error_requests" { + count = var.authorization_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Table Storage too many authorization errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.authorization_error_requests_message, var.message) + + query = < ${var.authorization_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.authorization_error_requests_threshold_critical + warning = var.authorization_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.authorization_error_requests_extra_tags) +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/storage/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/storage/outputs.tf new file mode 100755 index 0000000..9edd5e0 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/storage/outputs.tf @@ -0,0 +1,165 @@ +output "blob_authorization_error_requests_id" { + description = "id for monitor blob_authorization_error_requests" + value = datadog_monitor.blob_authorization_error_requests.*.id +} + +output "blob_client_other_error_requests_id" { + description = "id for monitor blob_client_other_error_requests" + value = datadog_monitor.blob_client_other_error_requests.*.id +} + +output "blob_network_error_requests_id" { + description = "id for monitor blob_network_error_requests" + value = datadog_monitor.blob_network_error_requests.*.id +} + +output "blob_server_other_error_requests_id" { + description = "id for monitor blob_server_other_error_requests" + value = datadog_monitor.blob_server_other_error_requests.*.id +} + +output "blob_throttling_error_requests_id" { + description = "id for monitor blob_throttling_error_requests" + value = datadog_monitor.blob_throttling_error_requests.*.id +} + +output "blob_timeout_error_requests_id" { + description = "id for monitor blob_timeout_error_requests" + value = datadog_monitor.blob_timeout_error_requests.*.id +} + +output "blobservices_latency_id" { + description = "id for monitor blobservices_latency" + value = datadog_monitor.blobservices_latency.*.id +} + +output "blobservices_requests_error_id" { + description = "id for monitor blobservices_requests_error" + value = datadog_monitor.blobservices_requests_error.*.id +} + +output "file_authorization_error_requests_id" { + description = "id for monitor file_authorization_error_requests" + value = datadog_monitor.file_authorization_error_requests.*.id +} + +output "file_client_other_error_requests_id" { + description = "id for monitor file_client_other_error_requests" + value = datadog_monitor.file_client_other_error_requests.*.id +} + +output "file_network_error_requests_id" { + description = "id for monitor file_network_error_requests" + value = datadog_monitor.file_network_error_requests.*.id +} + +output "file_server_other_error_requests_id" { + description = "id for monitor file_server_other_error_requests" + value = datadog_monitor.file_server_other_error_requests.*.id +} + +output "file_throttling_error_requests_id" { + description = "id for monitor file_throttling_error_requests" + value = datadog_monitor.file_throttling_error_requests.*.id +} + +output "file_timeout_error_requests_id" { + description = "id for monitor file_timeout_error_requests" + value = datadog_monitor.file_timeout_error_requests.*.id +} + +output "fileservices_latency_id" { + description = "id for monitor fileservices_latency" + value = datadog_monitor.fileservices_latency.*.id +} + +output "fileservices_requests_error_id" { + description = "id for monitor fileservices_requests_error" + value = datadog_monitor.fileservices_requests_error.*.id +} + +output "queue_authorization_error_requests_id" { + description = "id for monitor queue_authorization_error_requests" + value = datadog_monitor.queue_authorization_error_requests.*.id +} + +output "queue_client_other_error_requests_id" { + description = "id for monitor queue_client_other_error_requests" + value = datadog_monitor.queue_client_other_error_requests.*.id +} + +output "queue_network_error_requests_id" { + description = "id for monitor queue_network_error_requests" + value = datadog_monitor.queue_network_error_requests.*.id +} + +output "queue_server_other_error_requests_id" { + description = "id for monitor queue_server_other_error_requests" + value = datadog_monitor.queue_server_other_error_requests.*.id +} + +output "queue_throttling_error_requests_id" { + description = "id for monitor queue_throttling_error_requests" + value = datadog_monitor.queue_throttling_error_requests.*.id +} + +output "queue_timeout_error_requests_id" { + description = "id for monitor queue_timeout_error_requests" + value = datadog_monitor.queue_timeout_error_requests.*.id +} + +output "queueservices_latency_id" { + description = "id for monitor queueservices_latency" + value = datadog_monitor.queueservices_latency.*.id +} + +output "queueservices_requests_error_id" { + description = "id for monitor queueservices_requests_error" + value = datadog_monitor.queueservices_requests_error.*.id +} + +output "storage_status_id" { + description = "id for monitor storage_status" + value = datadog_monitor.storage_status.*.id +} + +output "table_authorization_error_requests_id" { + description = "id for monitor table_authorization_error_requests" + value = datadog_monitor.table_authorization_error_requests.*.id +} + +output "table_client_other_error_requests_id" { + description = "id for monitor table_client_other_error_requests" + value = datadog_monitor.table_client_other_error_requests.*.id +} + +output "table_network_error_requests_id" { + description = "id for monitor table_network_error_requests" + value = datadog_monitor.table_network_error_requests.*.id +} + +output "table_server_other_error_requests_id" { + description = "id for monitor table_server_other_error_requests" + value = datadog_monitor.table_server_other_error_requests.*.id +} + +output "table_throttling_error_requests_id" { + description = "id for monitor table_throttling_error_requests" + value = datadog_monitor.table_throttling_error_requests.*.id +} + +output "table_timeout_error_requests_id" { + description = "id for monitor table_timeout_error_requests" + value = datadog_monitor.table_timeout_error_requests.*.id +} + +output "tableservices_latency_id" { + description = "id for monitor tableservices_latency" + value = datadog_monitor.tableservices_latency.*.id +} + +output "tableservices_requests_error_id" { + description = "id for monitor tableservices_requests_error" + value = datadog_monitor.tableservices_requests_error.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/storage/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/storage/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/storage/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/stream-analytics/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/stream-analytics/README.md new file mode 100755 index 0000000..729cfb8 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/stream-analytics/README.md @@ -0,0 +1,114 @@ +# CLOUD AZURE STREAM-ANALYTICS DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-stream-analytics" { + source = "claranet/monitors/datadog//cloud/azure/stream-analytics" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Stream Analytics is down +- Stream Analytics streaming units utilization too high +- Stream Analytics too many conversion errors +- Stream Analytics too many failed requests +- Stream Analytics too many runtime errors + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.conversion_errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.failed_function_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.runtime_errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.su_utilization](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [conversion\_errors\_enabled](#input\_conversion\_errors\_enabled) | Flag to enable Stream Analytics conversion errors monitor | `string` | `"true"` | no | +| [conversion\_errors\_extra\_tags](#input\_conversion\_errors\_extra\_tags) | Extra tags for Stream Analytics conversion errors monitor | `list(string)` | `[]` | no | +| [conversion\_errors\_message](#input\_conversion\_errors\_message) | Custom message for Stream Analytics conversion errors monitor | `string` | `""` | no | +| [conversion\_errors\_threshold\_critical](#input\_conversion\_errors\_threshold\_critical) | Conversion errors limit (critical threshold) | `number` | `10` | no | +| [conversion\_errors\_threshold\_warning](#input\_conversion\_errors\_threshold\_warning) | Conversion errors limit (warning threshold) | `number` | `0` | no | +| [conversion\_errors\_time\_aggregator](#input\_conversion\_errors\_time\_aggregator) | Monitor aggregator for Stream Analytics conversion errors [available values: min, max or avg] | `string` | `"min"` | no | +| [conversion\_errors\_timeframe](#input\_conversion\_errors\_timeframe) | Monitor timeframe for Stream Analytics conversion errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [failed\_function\_requests\_enabled](#input\_failed\_function\_requests\_enabled) | Flag to enable Stream Analytics failed requests monitor | `string` | `"true"` | no | +| [failed\_function\_requests\_extra\_tags](#input\_failed\_function\_requests\_extra\_tags) | Extra tags for Stream Analytics failed requests monitor | `list(string)` | `[]` | no | +| [failed\_function\_requests\_message](#input\_failed\_function\_requests\_message) | Custom message for Stream Analytics failed requests monitor | `string` | `""` | no | +| [failed\_function\_requests\_threshold\_critical](#input\_failed\_function\_requests\_threshold\_critical) | Failed Function Request rate limit (critical threshold) | `number` | `10` | no | +| [failed\_function\_requests\_threshold\_warning](#input\_failed\_function\_requests\_threshold\_warning) | Failed Function Request rate limit (warning threshold) | `number` | `0` | no | +| [failed\_function\_requests\_time\_aggregator](#input\_failed\_function\_requests\_time\_aggregator) | Monitor aggregator for Stream Analytics failed requests [available values: min, max or avg] | `string` | `"min"` | no | +| [failed\_function\_requests\_timeframe](#input\_failed\_function\_requests\_timeframe) | Monitor timeframe for Stream Analytics failed requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a Redis monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [runtime\_errors\_enabled](#input\_runtime\_errors\_enabled) | Flag to enable Stream Analytics runtime errors monitor | `string` | `"true"` | no | +| [runtime\_errors\_extra\_tags](#input\_runtime\_errors\_extra\_tags) | Extra tags for Stream Analytics runtime errors monitor | `list(string)` | `[]` | no | +| [runtime\_errors\_message](#input\_runtime\_errors\_message) | Custom message for Stream Analytics runtime errors monitor | `string` | `""` | no | +| [runtime\_errors\_threshold\_critical](#input\_runtime\_errors\_threshold\_critical) | Runtime errors limit (critical threshold) | `number` | `10` | no | +| [runtime\_errors\_threshold\_warning](#input\_runtime\_errors\_threshold\_warning) | Runtime errors limit (warning threshold) | `number` | `0` | no | +| [runtime\_errors\_time\_aggregator](#input\_runtime\_errors\_time\_aggregator) | Monitor aggregator for Stream Analytics runtime errors [available values: min, max or avg] | `string` | `"min"` | no | +| [runtime\_errors\_timeframe](#input\_runtime\_errors\_timeframe) | Monitor timeframe for Stream Analytics runtime errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable Stream Analytics status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for Stream Analytics status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for Stream Analytics status monitor | `string` | `""` | no | +| [status\_no\_data\_timeframe](#input\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for Stream Analytics status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for Stream Analytics status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [su\_utilization\_enabled](#input\_su\_utilization\_enabled) | Flag to enable Stream Analytics utilization monitor | `string` | `"true"` | no | +| [su\_utilization\_extra\_tags](#input\_su\_utilization\_extra\_tags) | Extra tags for Stream Analytics utilization monitor | `list(string)` | `[]` | no | +| [su\_utilization\_message](#input\_su\_utilization\_message) | Custom message for Stream Analytics utilization monitor | `string` | `""` | no | +| [su\_utilization\_threshold\_critical](#input\_su\_utilization\_threshold\_critical) | Streaming Unit utilization rate limit (critical threshold) | `number` | `95` | no | +| [su\_utilization\_threshold\_warning](#input\_su\_utilization\_threshold\_warning) | Streaming Unit utilization rate limit (warning threshold) | `number` | `80` | no | +| [su\_utilization\_time\_aggregator](#input\_su\_utilization\_time\_aggregator) | Monitor aggregator for Stream Analytics utilization [available values: min, max or avg] | `string` | `"min"` | no | +| [su\_utilization\_timeframe](#input\_su\_utilization\_timeframe) | Monitor timeframe for Stream Analytics utilization [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [conversion\_errors\_id](#output\_conversion\_errors\_id) | id for monitor conversion\_errors | +| [failed\_function\_requests\_id](#output\_failed\_function\_requests\_id) | id for monitor failed\_function\_requests | +| [runtime\_errors\_id](#output\_runtime\_errors\_id) | id for monitor runtime\_errors | +| [status\_id](#output\_status\_id) | id for monitor status | +| [su\_utilization\_id](#output\_su\_utilization\_id) | id for monitor su\_utilization | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure/](https://docs.datadoghq.com/integrations/azure/) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/stream-analytics/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/stream-analytics/inputs.tf new file mode 100755 index 0000000..fd4ba71 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/stream-analytics/inputs.tf @@ -0,0 +1,244 @@ +# Global Terraform +variable "environment" { + description = "Architecture environment" + type = string +} + +# Global DataDog +variable "message" { + description = "Message sent when a Redis monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Azure Stream Analytics specific variables + +variable "status_enabled" { + description = "Flag to enable Stream Analytics status monitor" + type = string + default = "true" +} + +variable "status_extra_tags" { + description = "Extra tags for Stream Analytics status monitor" + type = list(string) + default = [] +} + +variable "status_message" { + description = "Custom message for Stream Analytics status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for Stream Analytics status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for Stream Analytics status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "su_utilization_enabled" { + description = "Flag to enable Stream Analytics utilization monitor" + type = string + default = "true" +} + +variable "su_utilization_extra_tags" { + description = "Extra tags for Stream Analytics utilization monitor" + type = list(string) + default = [] +} + +variable "su_utilization_message" { + description = "Custom message for Stream Analytics utilization monitor" + type = string + default = "" +} + +variable "su_utilization_time_aggregator" { + description = "Monitor aggregator for Stream Analytics utilization [available values: min, max or avg]" + type = string + default = "min" +} + +variable "su_utilization_timeframe" { + description = "Monitor timeframe for Stream Analytics utilization [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "su_utilization_threshold_warning" { + description = "Streaming Unit utilization rate limit (warning threshold)" + default = 80 +} + +variable "su_utilization_threshold_critical" { + description = "Streaming Unit utilization rate limit (critical threshold)" + default = 95 +} + +variable "failed_function_requests_enabled" { + description = "Flag to enable Stream Analytics failed requests monitor" + type = string + default = "true" +} + +variable "failed_function_requests_extra_tags" { + description = "Extra tags for Stream Analytics failed requests monitor" + type = list(string) + default = [] +} + +variable "failed_function_requests_message" { + description = "Custom message for Stream Analytics failed requests monitor" + type = string + default = "" +} + +variable "failed_function_requests_time_aggregator" { + description = "Monitor aggregator for Stream Analytics failed requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "failed_function_requests_timeframe" { + description = "Monitor timeframe for Stream Analytics failed requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_function_requests_threshold_warning" { + description = "Failed Function Request rate limit (warning threshold)" + default = 0 +} + +variable "failed_function_requests_threshold_critical" { + description = "Failed Function Request rate limit (critical threshold)" + default = 10 +} + +variable "conversion_errors_enabled" { + description = "Flag to enable Stream Analytics conversion errors monitor" + type = string + default = "true" +} + +variable "conversion_errors_extra_tags" { + description = "Extra tags for Stream Analytics conversion errors monitor" + type = list(string) + default = [] +} + +variable "conversion_errors_message" { + description = "Custom message for Stream Analytics conversion errors monitor" + type = string + default = "" +} + +variable "conversion_errors_time_aggregator" { + description = "Monitor aggregator for Stream Analytics conversion errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "conversion_errors_timeframe" { + description = "Monitor timeframe for Stream Analytics conversion errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "conversion_errors_threshold_warning" { + description = "Conversion errors limit (warning threshold)" + default = 0 +} + +variable "conversion_errors_threshold_critical" { + description = "Conversion errors limit (critical threshold)" + default = 10 +} + +variable "runtime_errors_enabled" { + description = "Flag to enable Stream Analytics runtime errors monitor" + type = string + default = "true" +} + +variable "runtime_errors_extra_tags" { + description = "Extra tags for Stream Analytics runtime errors monitor" + type = list(string) + default = [] +} + +variable "runtime_errors_message" { + description = "Custom message for Stream Analytics runtime errors monitor" + type = string + default = "" +} + +variable "runtime_errors_time_aggregator" { + description = "Monitor aggregator for Stream Analytics runtime errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "runtime_errors_timeframe" { + description = "Monitor timeframe for Stream Analytics runtime errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "runtime_errors_threshold_warning" { + description = "Runtime errors limit (warning threshold)" + default = 0 +} + +variable "runtime_errors_threshold_critical" { + description = "Runtime errors limit (critical threshold)" + default = 10 +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/stream-analytics/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/stream-analytics/modules.tf new file mode 100755 index 0000000..868c6a9 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/stream-analytics/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_stream-analytics" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/stream-analytics/monitors-stream-analytics.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/stream-analytics/monitors-stream-analytics.tf new file mode 100755 index 0000000..d7f30ca --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/stream-analytics/monitors-stream-analytics.tf @@ -0,0 +1,147 @@ +resource "datadog_monitor" "status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Stream Analytics is down" + message = coalesce(var.status_message, var.message) + type = "query alert" + + query = < ${var.su_utilization_threshold_critical} +EOQ + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + monitor_thresholds { + warning = var.su_utilization_threshold_warning + critical = var.su_utilization_threshold_critical + } + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:stream-analytics", "team:claranet", "created-by:terraform"], var.su_utilization_extra_tags) +} + +resource "datadog_monitor" "failed_function_requests" { + count = var.failed_function_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Stream Analytics too many failed requests {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.failed_function_requests_message, var.message) + type = "query alert" + + query = < ${var.failed_function_requests_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.failed_function_requests_threshold_warning + critical = var.failed_function_requests_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 60 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:stream-analytics", "team:claranet", "created-by:terraform"], var.failed_function_requests_extra_tags) +} + +resource "datadog_monitor" "conversion_errors" { + count = var.conversion_errors_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Stream Analytics too many conversion errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.conversion_errors_message, var.message) + type = "query alert" + + query = < ${var.conversion_errors_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.conversion_errors_threshold_warning + critical = var.conversion_errors_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:stream-analytics", "team:claranet", "created-by:terraform"], var.conversion_errors_extra_tags) +} + +resource "datadog_monitor" "runtime_errors" { + count = var.runtime_errors_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Stream Analytics too many runtime errors {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.runtime_errors_message, var.message) + type = "query alert" + + query = < ${var.runtime_errors_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.runtime_errors_threshold_warning + critical = var.runtime_errors_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:stream-analytics", "team:claranet", "created-by:terraform"], var.runtime_errors_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/stream-analytics/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/stream-analytics/outputs.tf new file mode 100755 index 0000000..c9ac170 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/stream-analytics/outputs.tf @@ -0,0 +1,25 @@ +output "conversion_errors_id" { + description = "id for monitor conversion_errors" + value = datadog_monitor.conversion_errors.*.id +} + +output "failed_function_requests_id" { + description = "id for monitor failed_function_requests" + value = datadog_monitor.failed_function_requests.*.id +} + +output "runtime_errors_id" { + description = "id for monitor runtime_errors" + value = datadog_monitor.runtime_errors.*.id +} + +output "status_id" { + description = "id for monitor status" + value = datadog_monitor.status.*.id +} + +output "su_utilization_id" { + description = "id for monitor su_utilization" + value = datadog_monitor.su_utilization.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/stream-analytics/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/stream-analytics/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/stream-analytics/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/virtual-machine/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/virtual-machine/README.md new file mode 100755 index 0000000..611e53f --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/virtual-machine/README.md @@ -0,0 +1,124 @@ +# CLOUD AZURE VIRTUAL-MACHINE DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-virtual-machine" { + source = "claranet/monitors/datadog//cloud/azure/virtual-machine" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Virtual Machine CPU usage +- Virtual Machine credit CPU +- Virtual Machine disk space +- Virtual Machine is unreachable +- Virtual Machine RAM reserved +- Virtual Machine requests failed + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.virtualmachine_cpu_usage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.virtualmachine_credit_cpu_remaining_too_low](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.virtualmachine_disk_space](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.virtualmachine_ram_reserved](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.virtualmachine_requests_failed](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.virtualmachine_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_remaining\_rate\_enabled](#input\_cpu\_remaining\_rate\_enabled) | Flag to enable Virtual Machine CPU remaining monitor | `string` | `"true"` | no | +| [cpu\_remaining\_rate\_extra\_tags](#input\_cpu\_remaining\_rate\_extra\_tags) | Extra tags for Virtual Machine CPU remaining monitor | `list(string)` | `[]` | no | +| [cpu\_remaining\_rate\_message](#input\_cpu\_remaining\_rate\_message) | Custom message for Virtual Machine CPU remaining monitor | `string` | `""` | no | +| [cpu\_remaining\_rate\_threshold\_critical](#input\_cpu\_remaining\_rate\_threshold\_critical) | Virtual Machine CPU rate limit (critical threshold) | `number` | `15` | no | +| [cpu\_remaining\_rate\_threshold\_warning](#input\_cpu\_remaining\_rate\_threshold\_warning) | Virtual Machine CPU rate limit (warning threshold) | `number` | `30` | no | +| [cpu\_remaining\_rate\_time\_aggregator](#input\_cpu\_remaining\_rate\_time\_aggregator) | Monitor aggregator for Virtual Machine CPU remaining [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [cpu\_remaining\_rate\_timeframe](#input\_cpu\_remaining\_rate\_timeframe) | Monitor timeframe for Virtual Machine CPU remaining [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [cpu\_usage\_enabled](#input\_cpu\_usage\_enabled) | Flag to enable Virtual Machine status monitor | `string` | `"true"` | no | +| [cpu\_usage\_extra\_tags](#input\_cpu\_usage\_extra\_tags) | Extra tags for Virtual Machine status monitor | `list(string)` | `[]` | no | +| [cpu\_usage\_message](#input\_cpu\_usage\_message) | Custom message for Virtual Machine CPU monitor | `string` | `""` | no | +| [cpu\_usage\_threshold\_critical](#input\_cpu\_usage\_threshold\_critical) | Virtual Machine CPU usage in percent (critical threshold) | `string` | `"90"` | no | +| [cpu\_usage\_threshold\_warning](#input\_cpu\_usage\_threshold\_warning) | Virtual Machine CPU usage in percent (warning threshold) | `string` | `"80"` | no | +| [cpu\_usage\_time\_aggregator](#input\_cpu\_usage\_time\_aggregator) | Monitor aggregator for Virtual Machine CPU [available values: min, max or avg] | `string` | `"min"` | no | +| [cpu\_usage\_timeframe](#input\_cpu\_usage\_timeframe) | Monitor timeframe for Virtual Machine CPU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [disk\_space\_enabled](#input\_disk\_space\_enabled) | Flag to enable Virtual Machine status monitor | `string` | `"true"` | no | +| [disk\_space\_extra\_tags](#input\_disk\_space\_extra\_tags) | Extra tags for Virtual Machine free disk space monitor | `list(string)` | `[]` | no | +| [disk\_space\_message](#input\_disk\_space\_message) | Custom message for Virtual Machine CPU free disk space monitor | `string` | `""` | no | +| [disk\_space\_threshold\_critical](#input\_disk\_space\_threshold\_critical) | Virtual Machine free disk space in percent (critical threshold) | `string` | `"95"` | no | +| [disk\_space\_threshold\_warning](#input\_disk\_space\_threshold\_warning) | Virtual Machine free disk space in percent (warning threshold) | `string` | `"90"` | no | +| [disk\_space\_time\_aggregator](#input\_disk\_space\_time\_aggregator) | Monitor aggregator for Virtual Machine free disk space [available values: min, max or avg] | `string` | `"max"` | no | +| [disk\_space\_timeframe](#input\_disk\_space\_timeframe) | Monitor timeframe for Virtual Machine free disk space too low [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a Redis monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [ram\_reserved\_enabled](#input\_ram\_reserved\_enabled) | Flag to enable Virtual Machine RAM reserved monitor | `string` | `"true"` | no | +| [ram\_reserved\_extra\_tags](#input\_ram\_reserved\_extra\_tags) | Extra tags for Virtual Machine RAM reserved monitor | `list(string)` | `[]` | no | +| [ram\_reserved\_message](#input\_ram\_reserved\_message) | Custom message for Virtual Machine RAM reserved monitor | `string` | `""` | no | +| [ram\_reserved\_threshold\_critical](#input\_ram\_reserved\_threshold\_critical) | Virtual Machine RAM reserved limit (critical threshold) | `number` | `95` | no | +| [ram\_reserved\_threshold\_warning](#input\_ram\_reserved\_threshold\_warning) | Virtual Machine RAM reserved limit (warning threshold) | `number` | `90` | no | +| [ram\_reserved\_time\_aggregator](#input\_ram\_reserved\_time\_aggregator) | Monitor aggregator for Virtual Machine RAM reserved [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [ram\_reserved\_timeframe](#input\_ram\_reserved\_timeframe) | Monitor timeframe for Virtual Machine RAM reserved [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [requests\_failed\_enabled](#input\_requests\_failed\_enabled) | Flag to enable Virtual Machine requests failed monitor | `string` | `"true"` | no | +| [requests\_failed\_extra\_tags](#input\_requests\_failed\_extra\_tags) | Extra tags for Virtual Machine requests failed monitor | `list(string)` | `[]` | no | +| [requests\_failed\_message](#input\_requests\_failed\_message) | Custom message for Virtual Machine requests failed monitor | `string` | `""` | no | +| [requests\_failed\_threshold\_critical](#input\_requests\_failed\_threshold\_critical) | Virtual Machine requests failed limit (critical threshold) | `number` | `95` | no | +| [requests\_failed\_threshold\_warning](#input\_requests\_failed\_threshold\_warning) | Virtual Machine requests failed limit (warning threshold) | `number` | `90` | no | +| [requests\_failed\_time\_aggregator](#input\_requests\_failed\_time\_aggregator) | Monitor aggregator for Virtual Machine requests failed [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [requests\_failed\_timeframe](#input\_requests\_failed\_timeframe) | Monitor timeframe for Virtual Machine requests failed [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_10m"` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable Virtual Machine status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for Virtual Machine status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for Virtual Machine status monitor | `string` | `""` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for Virtual Machine status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for Virtual Machine status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [virtualmachine\_status\_no\_data\_timeframe](#input\_virtualmachine\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [virtualmachine\_cpu\_usage\_id](#output\_virtualmachine\_cpu\_usage\_id) | id for monitor virtualmachine\_cpu\_usage | +| [virtualmachine\_credit\_cpu\_remaining\_too\_low\_id](#output\_virtualmachine\_credit\_cpu\_remaining\_too\_low\_id) | id for monitor virtualmachine\_credit\_cpu\_remaining\_too\_low | +| [virtualmachine\_disk\_space\_id](#output\_virtualmachine\_disk\_space\_id) | id for monitor virtualmachine\_disk\_space | +| [virtualmachine\_ram\_reserved\_id](#output\_virtualmachine\_ram\_reserved\_id) | id for monitor virtualmachine\_ram\_reserved | +| [virtualmachine\_requests\_failed\_id](#output\_virtualmachine\_requests\_failed\_id) | id for monitor virtualmachine\_requests\_failed | +| [virtualmachine\_status\_id](#output\_virtualmachine\_status\_id) | id for monitor virtualmachine\_status | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure_vm/](https://docs.datadoghq.com/integrations/azure_vm/) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/virtual-machine/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/virtual-machine/inputs.tf new file mode 100755 index 0000000..336e341 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/virtual-machine/inputs.tf @@ -0,0 +1,283 @@ +# Global Terraform +variable "environment" { + description = "Architecture environment" + type = string +} + +# Global DataDog +variable "message" { + description = "Message sent when a Redis monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "virtualmachine_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Azure Virtual Machine specific variables + +variable "status_enabled" { + description = "Flag to enable Virtual Machine status monitor" + type = string + default = "true" +} + +variable "status_extra_tags" { + description = "Extra tags for Virtual Machine status monitor" + type = list(string) + default = [] +} + +variable "status_message" { + description = "Custom message for Virtual Machine status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for Virtual Machine status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for Virtual Machine status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "cpu_usage_enabled" { + description = "Flag to enable Virtual Machine status monitor" + type = string + default = "true" +} + +variable "cpu_usage_extra_tags" { + description = "Extra tags for Virtual Machine status monitor" + type = list(string) + default = [] +} + +variable "cpu_usage_message" { + description = "Custom message for Virtual Machine CPU monitor" + type = string + default = "" +} + +variable "cpu_usage_time_aggregator" { + description = "Monitor aggregator for Virtual Machine CPU [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cpu_usage_timeframe" { + description = "Monitor timeframe for Virtual Machine CPU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "cpu_usage_threshold_warning" { + description = "Virtual Machine CPU usage in percent (warning threshold)" + default = "80" +} + +variable "cpu_usage_threshold_critical" { + description = "Virtual Machine CPU usage in percent (critical threshold)" + default = "90" +} + +variable "cpu_remaining_rate_enabled" { + description = "Flag to enable Virtual Machine CPU remaining monitor" + type = string + default = "true" +} + +variable "cpu_remaining_rate_extra_tags" { + description = "Extra tags for Virtual Machine CPU remaining monitor" + type = list(string) + default = [] +} + +variable "cpu_remaining_rate_message" { + description = "Custom message for Virtual Machine CPU remaining monitor" + type = string + default = "" +} + +variable "cpu_remaining_rate_time_aggregator" { + description = "Monitor aggregator for Virtual Machine CPU remaining [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "cpu_remaining_rate_timeframe" { + description = "Monitor timeframe for Virtual Machine CPU remaining [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "cpu_remaining_rate_threshold_warning" { + description = "Virtual Machine CPU rate limit (warning threshold)" + default = 30 +} + +variable "cpu_remaining_rate_threshold_critical" { + description = "Virtual Machine CPU rate limit (critical threshold)" + default = 15 +} + +variable "ram_reserved_enabled" { + description = "Flag to enable Virtual Machine RAM reserved monitor" + type = string + default = "true" +} + +variable "ram_reserved_message" { + description = "Custom message for Virtual Machine RAM reserved monitor" + type = string + default = "" +} + +variable "ram_reserved_extra_tags" { + description = "Extra tags for Virtual Machine RAM reserved monitor" + type = list(string) + default = [] +} + +variable "ram_reserved_time_aggregator" { + description = "Monitor aggregator for Virtual Machine RAM reserved [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "ram_reserved_timeframe" { + description = "Monitor timeframe for Virtual Machine RAM reserved [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "ram_reserved_threshold_warning" { + description = "Virtual Machine RAM reserved limit (warning threshold)" + default = 90 +} + +variable "ram_reserved_threshold_critical" { + description = "Virtual Machine RAM reserved limit (critical threshold)" + default = 95 +} + +variable "disk_space_enabled" { + description = "Flag to enable Virtual Machine status monitor" + type = string + default = "true" +} + +variable "disk_space_time_aggregator" { + description = "Monitor aggregator for Virtual Machine free disk space [available values: min, max or avg]" + type = string + default = "max" +} + +variable "disk_space_timeframe" { + description = "Monitor timeframe for Virtual Machine free disk space too low [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "disk_space_threshold_critical" { + description = "Virtual Machine free disk space in percent (critical threshold)" + default = "95" +} + +variable "disk_space_threshold_warning" { + description = "Virtual Machine free disk space in percent (warning threshold)" + default = "90" +} + +variable "disk_space_extra_tags" { + description = "Extra tags for Virtual Machine free disk space monitor" + type = list(string) + default = [] +} + +variable "disk_space_message" { + description = "Custom message for Virtual Machine CPU free disk space monitor" + type = string + default = "" +} + +variable "requests_failed_enabled" { + description = "Flag to enable Virtual Machine requests failed monitor" + type = string + default = "true" +} + +variable "requests_failed_message" { + description = "Custom message for Virtual Machine requests failed monitor" + type = string + default = "" +} + +variable "requests_failed_extra_tags" { + description = "Extra tags for Virtual Machine requests failed monitor" + type = list(string) + default = [] +} + +variable "requests_failed_time_aggregator" { + description = "Monitor aggregator for Virtual Machine requests failed [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "requests_failed_timeframe" { + description = "Monitor timeframe for Virtual Machine requests failed [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_10m" +} + +variable "requests_failed_threshold_warning" { + description = "Virtual Machine requests failed limit (warning threshold)" + default = 90 +} + +variable "requests_failed_threshold_critical" { + description = "Virtual Machine requests failed limit (critical threshold)" + default = 95 +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/virtual-machine/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/virtual-machine/modules.tf new file mode 100755 index 0000000..8be2bf9 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/virtual-machine/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_virtual-machine" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/virtual-machine/monitors-virtual-machine.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/virtual-machine/monitors-virtual-machine.tf new file mode 100755 index 0000000..d952b4c --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/virtual-machine/monitors-virtual-machine.tf @@ -0,0 +1,183 @@ +resource "datadog_monitor" "virtualmachine_status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Virtual Machine is unreachable" + message = coalesce(var.status_message, var.message) + type = "query alert" + + query = < ${var.cpu_usage_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.cpu_usage_threshold_critical + warning = var.cpu_usage_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:virtualmachine", "team:claranet", "created-by:terraform"], var.cpu_usage_extra_tags) +} + +resource "datadog_monitor" "virtualmachine_credit_cpu_remaining_too_low" { + count = var.cpu_remaining_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Virtual Machine credit CPU {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cpu_remaining_rate_message, var.message) + type = "query alert" + + query = < ${var.ram_reserved_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.ram_reserved_threshold_critical + warning = var.ram_reserved_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:virtualmachine", "team:claranet", "created-by:terraform"], var.ram_reserved_extra_tags) +} + +resource "datadog_monitor" "virtualmachine_disk_space" { + count = var.disk_space_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Virtual Machine disk space {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.disk_space_message, var.message) + type = "query alert" + + query = < ${var.disk_space_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.disk_space_threshold_warning + critical = var.disk_space_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:virtualmachine", "team:claranet", "created-by:terraform"], var.disk_space_extra_tags) +} + +resource "datadog_monitor" "virtualmachine_requests_failed" { + count = var.requests_failed_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Virtual Machine requests failed {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.requests_failed_message, var.message) + type = "query alert" + + query = < ${var.requests_failed_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.requests_failed_threshold_critical + warning = var.requests_failed_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:virtualmachine", "team:claranet", "created-by:terraform"], var.requests_failed_extra_tags) +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/virtual-machine/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/virtual-machine/outputs.tf new file mode 100755 index 0000000..fe9bffd --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/virtual-machine/outputs.tf @@ -0,0 +1,30 @@ +output "virtualmachine_cpu_usage_id" { + description = "id for monitor virtualmachine_cpu_usage" + value = datadog_monitor.virtualmachine_cpu_usage.*.id +} + +output "virtualmachine_credit_cpu_remaining_too_low_id" { + description = "id for monitor virtualmachine_credit_cpu_remaining_too_low" + value = datadog_monitor.virtualmachine_credit_cpu_remaining_too_low.*.id +} + +output "virtualmachine_disk_space_id" { + description = "id for monitor virtualmachine_disk_space" + value = datadog_monitor.virtualmachine_disk_space.*.id +} + +output "virtualmachine_ram_reserved_id" { + description = "id for monitor virtualmachine_ram_reserved" + value = datadog_monitor.virtualmachine_ram_reserved.*.id +} + +output "virtualmachine_requests_failed_id" { + description = "id for monitor virtualmachine_requests_failed" + value = datadog_monitor.virtualmachine_requests_failed.*.id +} + +output "virtualmachine_status_id" { + description = "id for monitor virtualmachine_status" + value = datadog_monitor.virtualmachine_status.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/virtual-machine/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/virtual-machine/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/azure/virtual-machine/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/big-query/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/big-query/README.md new file mode 100755 index 0000000..8d378a5 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/big-query/README.md @@ -0,0 +1,144 @@ +# CLOUD GCP BIG-QUERY DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-gcp-big-query" { + source = "claranet/monitors/datadog//cloud/gcp/big-query" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- GCP Big Query Available Slots +- GCP Big Query Concurrent Queries +- GCP Big Query Execution Time +- GCP Big Query Scanned Bytes +- GCP Big Query Scanned Bytes Billed +- GCP Big Query Stored Bytes +- GCP Big Query Table Count +- GCP Big Query Uploaded Bytes +- GCP Big Query Uploaded Bytes Billed + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.available_slots](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.concurrent_queries](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.execution_time](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.scanned_bytes](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.scanned_bytes_billed](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.stored_bytes](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.table_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.uploaded_bytes](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.uploaded_bytes_billed](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [available\_slots\_enabled](#input\_available\_slots\_enabled) | Flag to enable GCP Big Query Available Slots monitor | `string` | `"true"` | no | +| [available\_slots\_extra\_tags](#input\_available\_slots\_extra\_tags) | Extra tags for GCP Big Query Available Slots monitor | `list(string)` | `[]` | no | +| [available\_slots\_message](#input\_available\_slots\_message) | Custom message for the Available Slots monitor | `string` | `""` | no | +| [available\_slots\_threshold\_critical](#input\_available\_slots\_threshold\_critical) | Available Slots (critical threshold) | `string` | `200` | no | +| [available\_slots\_threshold\_warning](#input\_available\_slots\_threshold\_warning) | Available Slots (warning threshold) | `string` | `300` | no | +| [available\_slots\_timeframe](#input\_available\_slots\_timeframe) | Timeframe for the Available Slots monitor | `string` | `"last_5m"` | no | +| [concurrent\_queries\_enabled](#input\_concurrent\_queries\_enabled) | Flag to enable GCP Big Query Concurrent Queries monitor | `string` | `"true"` | no | +| [concurrent\_queries\_extra\_tags](#input\_concurrent\_queries\_extra\_tags) | Extra tags for GCP Big Query Concurrent Queries monitor | `list(string)` | `[]` | no | +| [concurrent\_queries\_message](#input\_concurrent\_queries\_message) | Custom message for the Concurrent Queries monitor | `string` | `""` | no | +| [concurrent\_queries\_threshold\_critical](#input\_concurrent\_queries\_threshold\_critical) | Concurrent Queries (critical threshold) (hard limit 50) | `string` | `45` | no | +| [concurrent\_queries\_threshold\_warning](#input\_concurrent\_queries\_threshold\_warning) | Concurrent Queries (warning threshold) (hard limit 50) | `string` | `40` | no | +| [concurrent\_queries\_timeframe](#input\_concurrent\_queries\_timeframe) | Timeframe for the Concurrent Queries monitor | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [execution\_time\_enabled](#input\_execution\_time\_enabled) | Flag to enable GCP Big Query Execution Time monitor | `string` | `"true"` | no | +| [execution\_time\_extra\_tags](#input\_execution\_time\_extra\_tags) | Extra tags for GCP Big Query Execution Time monitor | `list(string)` | `[]` | no | +| [execution\_time\_message](#input\_execution\_time\_message) | Custom message for the Execution Time monitor | `string` | `""` | no | +| [execution\_time\_threshold\_critical](#input\_execution\_time\_threshold\_critical) | Average Execution Time in seconds (critical threshold) | `string` | `150` | no | +| [execution\_time\_threshold\_warning](#input\_execution\_time\_threshold\_warning) | Average Execution Time in seconds (warning threshold) | `string` | `100` | no | +| [execution\_time\_timeframe](#input\_execution\_time\_timeframe) | Timeframe for the Execution Time monitor | `string` | `"last_5m"` | no | +| [filter\_tags](#input\_filter\_tags) | Tags used for filtering | `string` | `"*"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the new host evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [scanned\_bytes\_billed\_enabled](#input\_scanned\_bytes\_billed\_enabled) | Flag to enable GCP Big Query Scanned Bytes Billed monitor | `string` | `"true"` | no | +| [scanned\_bytes\_billed\_extra\_tags](#input\_scanned\_bytes\_billed\_extra\_tags) | Extra tags for GCP Big Query Scanned Bytes Billed monitor | `list(string)` | `[]` | no | +| [scanned\_bytes\_billed\_message](#input\_scanned\_bytes\_billed\_message) | Custom message for the Scanned Bytes Billed monitor | `string` | `""` | no | +| [scanned\_bytes\_billed\_threshold\_critical](#input\_scanned\_bytes\_billed\_threshold\_critical) | Scanned Bytes Billed (critical threshold) | `string` | `1` | no | +| [scanned\_bytes\_billed\_threshold\_warning](#input\_scanned\_bytes\_billed\_threshold\_warning) | Scanned Bytes Billed (warning threshold) | `string` | `0` | no | +| [scanned\_bytes\_billed\_timeframe](#input\_scanned\_bytes\_billed\_timeframe) | Timeframe for the Scanned Bytes Billed monitor | `string` | `"last_4h"` | no | +| [scanned\_bytes\_enabled](#input\_scanned\_bytes\_enabled) | Flag to enable GCP Big Query Scanned Bytes monitor | `string` | `"true"` | no | +| [scanned\_bytes\_extra\_tags](#input\_scanned\_bytes\_extra\_tags) | Extra tags for GCP Big Query Scanned Bytes monitor | `list(string)` | `[]` | no | +| [scanned\_bytes\_message](#input\_scanned\_bytes\_message) | Custom message for the Scanned Bytes monitor | `string` | `""` | no | +| [scanned\_bytes\_threshold\_critical](#input\_scanned\_bytes\_threshold\_critical) | Scanned Bytes (critical threshold) | `string` | `1` | no | +| [scanned\_bytes\_threshold\_warning](#input\_scanned\_bytes\_threshold\_warning) | Scanned Bytes (warning threshold) | `string` | `0` | no | +| [scanned\_bytes\_timeframe](#input\_scanned\_bytes\_timeframe) | Timeframe for the Scanned Bytes monitor | `string` | `"last_4h"` | no | +| [stored\_bytes\_enabled](#input\_stored\_bytes\_enabled) | Flag to enable GCP Big Query Stored Bytes monitor | `string` | `"true"` | no | +| [stored\_bytes\_extra\_tags](#input\_stored\_bytes\_extra\_tags) | Extra tags for GCP Big Query Stored Bytes monitor | `list(string)` | `[]` | no | +| [stored\_bytes\_message](#input\_stored\_bytes\_message) | Custom message for the Stored Bytes monitor | `string` | `""` | no | +| [stored\_bytes\_threshold\_critical](#input\_stored\_bytes\_threshold\_critical) | Stored Bytes in fraction (critical threshold) | `string` | `1` | no | +| [stored\_bytes\_threshold\_warning](#input\_stored\_bytes\_threshold\_warning) | Stored Bytes in fraction (warning threshold) | `string` | `0` | no | +| [stored\_bytes\_timeframe](#input\_stored\_bytes\_timeframe) | Timeframe for the Stored Bytes monitor | `string` | `"last_5m"` | no | +| [table\_count\_enabled](#input\_table\_count\_enabled) | Flag to enable GCP Big Query Table Count monitor | `string` | `"true"` | no | +| [table\_count\_extra\_tags](#input\_table\_count\_extra\_tags) | Extra tags for GCP Big Query Table Count monitor | `list(string)` | `[]` | no | +| [table\_count\_message](#input\_table\_count\_message) | Custom message for the Table Count monitor | `string` | `""` | no | +| [table\_count\_threshold\_critical](#input\_table\_count\_threshold\_critical) | Table Count (critical threshold) | `string` | `1` | no | +| [table\_count\_threshold\_warning](#input\_table\_count\_threshold\_warning) | Table Count (warning threshold) | `string` | `0` | no | +| [table\_count\_timeframe](#input\_table\_count\_timeframe) | Timeframe for the Table Count monitor | `string` | `"last_4h"` | no | +| [uploaded\_bytes\_billed\_enabled](#input\_uploaded\_bytes\_billed\_enabled) | Flag to enable GCP Big Query Uploaded Bytes Billed monitor | `string` | `"true"` | no | +| [uploaded\_bytes\_billed\_extra\_tags](#input\_uploaded\_bytes\_billed\_extra\_tags) | Extra tags for GCP Big Query Scanned Bytes monitor | `list(string)` | `[]` | no | +| [uploaded\_bytes\_billed\_message](#input\_uploaded\_bytes\_billed\_message) | Custom message for the Uploaded Bytes Billed monitor | `string` | `""` | no | +| [uploaded\_bytes\_billed\_threshold\_critical](#input\_uploaded\_bytes\_billed\_threshold\_critical) | Uploaded Bytes Billed (critical threshold) | `string` | `1` | no | +| [uploaded\_bytes\_billed\_threshold\_warning](#input\_uploaded\_bytes\_billed\_threshold\_warning) | Uploaded Bytes Billed (warning threshold) | `string` | `0` | no | +| [uploaded\_bytes\_billed\_timeframe](#input\_uploaded\_bytes\_billed\_timeframe) | Timeframe for the Uploaded Bytes Billed monitor | `string` | `"last_4h"` | no | +| [uploaded\_bytes\_enabled](#input\_uploaded\_bytes\_enabled) | Flag to enable GCP Big Query Uploaded Bytes monitor | `string` | `"true"` | no | +| [uploaded\_bytes\_extra\_tags](#input\_uploaded\_bytes\_extra\_tags) | Extra tags for GCP Big Query Uploaded Bytes monitor | `list(string)` | `[]` | no | +| [uploaded\_bytes\_message](#input\_uploaded\_bytes\_message) | Custom message for the Uploaded Bytes monitor | `string` | `""` | no | +| [uploaded\_bytes\_threshold\_critical](#input\_uploaded\_bytes\_threshold\_critical) | Uploaded Bytes (critical threshold) | `string` | `1` | no | +| [uploaded\_bytes\_threshold\_warning](#input\_uploaded\_bytes\_threshold\_warning) | Uploaded Bytes (warning threshold) | `string` | `0` | no | +| [uploaded\_bytes\_timeframe](#input\_uploaded\_bytes\_timeframe) | Timeframe for the Uploaded Bytes monitor | `string` | `"last_4h"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [available\_slots\_id](#output\_available\_slots\_id) | id for monitor available\_slots | +| [concurrent\_queries\_id](#output\_concurrent\_queries\_id) | id for monitor concurrent\_queries | +| [execution\_time\_id](#output\_execution\_time\_id) | id for monitor execution\_time | +| [scanned\_bytes\_billed\_id](#output\_scanned\_bytes\_billed\_id) | id for monitor scanned\_bytes\_billed | +| [scanned\_bytes\_id](#output\_scanned\_bytes\_id) | id for monitor scanned\_bytes | +| [stored\_bytes\_id](#output\_stored\_bytes\_id) | id for monitor stored\_bytes | +| [table\_count\_id](#output\_table\_count\_id) | id for monitor table\_count | +| [uploaded\_bytes\_billed\_id](#output\_uploaded\_bytes\_billed\_id) | id for monitor uploaded\_bytes\_billed | +| [uploaded\_bytes\_id](#output\_uploaded\_bytes\_id) | id for monitor uploaded\_bytes | +## Related documentation + +* [GCP Big Query monitoring](https://cloud.google.com/bigquery/docs/monitoring) +* [Datadog Integration for GCP Big Query](https://docs.datadoghq.com/integrations/google_cloud_big_query/) +* [GCP Big Query Quotas and Limits](https://cloud.google.com/bigquery/quotas) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/big-query/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/big-query/inputs.tf new file mode 100755 index 0000000..71edb3c --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/big-query/inputs.tf @@ -0,0 +1,398 @@ +# +# Datadog global variables +# + +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags" { + description = "Tags used for filtering" + default = "*" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds for the new host evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# +# Concurrent queries +# + +variable "concurrent_queries_message" { + description = "Custom message for the Concurrent Queries monitor" + type = string + default = "" +} + +variable "concurrent_queries_timeframe" { + description = "Timeframe for the Concurrent Queries monitor" + type = string + default = "last_5m" +} + +variable "concurrent_queries_threshold_warning" { + description = "Concurrent Queries (warning threshold) (hard limit 50)" + type = string + default = 40 +} + +variable "concurrent_queries_threshold_critical" { + description = "Concurrent Queries (critical threshold) (hard limit 50)" + type = string + default = 45 +} + +variable "concurrent_queries_enabled" { + description = "Flag to enable GCP Big Query Concurrent Queries monitor" + type = string + default = "true" +} + +variable "concurrent_queries_extra_tags" { + description = "Extra tags for GCP Big Query Concurrent Queries monitor" + type = list(string) + default = [] +} + +# +# Execution Time +# + +variable "execution_time_message" { + description = "Custom message for the Execution Time monitor" + type = string + default = "" +} + +variable "execution_time_timeframe" { + description = "Timeframe for the Execution Time monitor" + type = string + default = "last_5m" +} + +variable "execution_time_threshold_warning" { + description = "Average Execution Time in seconds (warning threshold)" + type = string + default = 100 +} + +variable "execution_time_threshold_critical" { + description = "Average Execution Time in seconds (critical threshold)" + type = string + default = 150 +} + +variable "execution_time_enabled" { + description = "Flag to enable GCP Big Query Execution Time monitor" + type = string + default = "true" +} + +variable "execution_time_extra_tags" { + description = "Extra tags for GCP Big Query Execution Time monitor" + type = list(string) + default = [] +} + +# +# Scanned Bytes +# + +variable "scanned_bytes_message" { + description = "Custom message for the Scanned Bytes monitor" + type = string + default = "" +} + +variable "scanned_bytes_timeframe" { + description = "Timeframe for the Scanned Bytes monitor" + type = string + default = "last_4h" +} + +variable "scanned_bytes_threshold_warning" { + description = "Scanned Bytes (warning threshold)" + type = string + default = 0 +} + +variable "scanned_bytes_threshold_critical" { + description = "Scanned Bytes (critical threshold)" + type = string + default = 1 +} + +variable "scanned_bytes_enabled" { + description = "Flag to enable GCP Big Query Scanned Bytes monitor" + type = string + default = "true" +} + +variable "scanned_bytes_extra_tags" { + description = "Extra tags for GCP Big Query Scanned Bytes monitor" + type = list(string) + default = [] +} + +# +# Scanned Bytes Billed +# + +variable "scanned_bytes_billed_message" { + description = "Custom message for the Scanned Bytes Billed monitor" + type = string + default = "" +} + +variable "scanned_bytes_billed_timeframe" { + description = "Timeframe for the Scanned Bytes Billed monitor" + type = string + default = "last_4h" +} + +variable "scanned_bytes_billed_threshold_warning" { + description = "Scanned Bytes Billed (warning threshold)" + type = string + default = 0 +} + +variable "scanned_bytes_billed_threshold_critical" { + description = "Scanned Bytes Billed (critical threshold)" + type = string + default = 1 +} + +variable "scanned_bytes_billed_enabled" { + description = "Flag to enable GCP Big Query Scanned Bytes Billed monitor" + type = string + default = "true" +} + +variable "scanned_bytes_billed_extra_tags" { + description = "Extra tags for GCP Big Query Scanned Bytes Billed monitor" + type = list(string) + default = [] +} + +# +# Available Slots +# + +variable "available_slots_message" { + description = "Custom message for the Available Slots monitor" + type = string + default = "" +} + +variable "available_slots_timeframe" { + description = "Timeframe for the Available Slots monitor" + type = string + default = "last_5m" +} + +variable "available_slots_threshold_warning" { + description = "Available Slots (warning threshold)" + type = string + default = 300 +} + +variable "available_slots_threshold_critical" { + description = "Available Slots (critical threshold)" + type = string + default = 200 +} + +variable "available_slots_enabled" { + description = "Flag to enable GCP Big Query Available Slots monitor" + type = string + default = "true" +} + +variable "available_slots_extra_tags" { + description = "Extra tags for GCP Big Query Available Slots monitor" + type = list(string) + default = [] +} + +# +# Stored Bytes +# + +variable "stored_bytes_message" { + description = "Custom message for the Stored Bytes monitor" + type = string + default = "" +} + +variable "stored_bytes_timeframe" { + description = "Timeframe for the Stored Bytes monitor" + type = string + default = "last_5m" +} + +variable "stored_bytes_threshold_warning" { + description = "Stored Bytes in fraction (warning threshold)" + type = string + default = 0 +} + +variable "stored_bytes_threshold_critical" { + description = "Stored Bytes in fraction (critical threshold)" + type = string + default = 1 +} + +variable "stored_bytes_enabled" { + description = "Flag to enable GCP Big Query Stored Bytes monitor" + type = string + default = "true" +} + +variable "stored_bytes_extra_tags" { + description = "Extra tags for GCP Big Query Stored Bytes monitor" + type = list(string) + default = [] +} + +# +# Table Count +# + +variable "table_count_message" { + description = "Custom message for the Table Count monitor" + type = string + default = "" +} + +variable "table_count_timeframe" { + description = "Timeframe for the Table Count monitor" + type = string + default = "last_4h" +} + +variable "table_count_threshold_warning" { + description = "Table Count (warning threshold)" + type = string + default = 0 +} + +variable "table_count_threshold_critical" { + description = "Table Count (critical threshold)" + type = string + default = 1 +} + +variable "table_count_enabled" { + description = "Flag to enable GCP Big Query Table Count monitor" + type = string + default = "true" +} + +variable "table_count_extra_tags" { + description = "Extra tags for GCP Big Query Table Count monitor" + type = list(string) + default = [] +} + +# +# Uploaded Bytes +# + +variable "uploaded_bytes_message" { + description = "Custom message for the Uploaded Bytes monitor" + type = string + default = "" +} + +variable "uploaded_bytes_timeframe" { + description = "Timeframe for the Uploaded Bytes monitor" + type = string + default = "last_4h" +} + +variable "uploaded_bytes_threshold_warning" { + description = "Uploaded Bytes (warning threshold)" + type = string + default = 0 +} + +variable "uploaded_bytes_threshold_critical" { + description = "Uploaded Bytes (critical threshold)" + type = string + default = 1 +} + +variable "uploaded_bytes_enabled" { + description = "Flag to enable GCP Big Query Uploaded Bytes monitor" + type = string + default = "true" +} + +variable "uploaded_bytes_extra_tags" { + description = "Extra tags for GCP Big Query Uploaded Bytes monitor" + type = list(string) + default = [] +} + +# +# Uploaded Bytes Billed +# + +variable "uploaded_bytes_billed_message" { + description = "Custom message for the Uploaded Bytes Billed monitor" + type = string + default = "" +} + +variable "uploaded_bytes_billed_timeframe" { + description = "Timeframe for the Uploaded Bytes Billed monitor" + type = string + default = "last_4h" +} + +variable "uploaded_bytes_billed_threshold_warning" { + description = "Uploaded Bytes Billed (warning threshold)" + type = string + default = 0 +} + +variable "uploaded_bytes_billed_threshold_critical" { + description = "Uploaded Bytes Billed (critical threshold)" + type = string + default = 1 +} + +variable "uploaded_bytes_billed_enabled" { + description = "Flag to enable GCP Big Query Uploaded Bytes Billed monitor" + type = string + default = "true" +} + +variable "uploaded_bytes_billed_extra_tags" { + description = "Extra tags for GCP Big Query Scanned Bytes monitor" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/big-query/monitors-big-query.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/big-query/monitors-big-query.tf new file mode 100755 index 0000000..82ee6c4 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/big-query/monitors-big-query.tf @@ -0,0 +1,297 @@ +# +# Concurrent queries +# +resource "datadog_monitor" "concurrent_queries" { + count = var.concurrent_queries_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP Big Query Concurrent Queries {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.concurrent_queries_message, var.message) + type = "query alert" + + query = < ${var.concurrent_queries_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.concurrent_queries_threshold_warning + critical = var.concurrent_queries_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + include_tags = true + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:big-query", "team:claranet", "created-by:terraform"], var.concurrent_queries_extra_tags) +} + +# +# Execution Time +# +resource "datadog_monitor" "execution_time" { + count = var.execution_time_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP Big Query Execution Time {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + message = coalesce(var.execution_time_message, var.message) + type = "query alert" + + query = < ${var.execution_time_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.execution_time_threshold_warning + critical = var.execution_time_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + include_tags = true + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:big-query", "team:claranet", "created-by:terraform"], var.execution_time_extra_tags) +} + +# +# Scanned Bytes +# +resource "datadog_monitor" "scanned_bytes" { + count = var.scanned_bytes_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP Big Query Scanned Bytes {{#is_alert}}{{{comparator}}} {{threshold}}B/mn ({{value}}B/mn){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}B/mn ({{value}}B/mn){{/is_warning}}" + message = coalesce(var.scanned_bytes_message, var.message) + type = "query alert" + + query = < ${var.scanned_bytes_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.scanned_bytes_threshold_warning + critical = var.scanned_bytes_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + include_tags = true + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:big-query", "team:claranet", "created-by:terraform"], var.scanned_bytes_extra_tags) +} + +# +# Scanned Bytes Billed +# +resource "datadog_monitor" "scanned_bytes_billed" { + count = var.scanned_bytes_billed_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP Big Query Scanned Bytes Billed {{#is_alert}}{{{comparator}}} {{threshold}}B/mn ({{value}}B/mn){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}B/mn ({{value}}B/mn){{/is_warning}}" + message = coalesce(var.scanned_bytes_billed_message, var.message) + type = "query alert" + + query = < ${var.scanned_bytes_billed_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.scanned_bytes_billed_threshold_warning + critical = var.scanned_bytes_billed_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + include_tags = true + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:big-query", "team:claranet", "created-by:terraform"], var.scanned_bytes_billed_extra_tags) +} + +# +# Available Slots +# +resource "datadog_monitor" "available_slots" { + count = var.available_slots_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP Big Query Available Slots {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.available_slots_message, var.message) + type = "metric alert" + + query = < ${var.stored_bytes_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.stored_bytes_threshold_warning + critical = var.stored_bytes_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + include_tags = true + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:big-query", "team:claranet", "created-by:terraform"], var.stored_bytes_extra_tags) +} + +# +# Table Count +# +resource "datadog_monitor" "table_count" { + count = var.table_count_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP Big Query Table Count {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.table_count_message, var.message) + type = "metric alert" + + query = < ${var.table_count_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.table_count_threshold_warning + critical = var.table_count_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + include_tags = true + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:big-query", "team:claranet", "created-by:terraform"], var.table_count_extra_tags) +} + +# +# Uploaded Bytes +# +resource "datadog_monitor" "uploaded_bytes" { + count = var.uploaded_bytes_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP Big Query Uploaded Bytes {{#is_alert}}{{{comparator}}} {{threshold}}B/mn ({{value}}B/mn){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}B/mn ({{value}}B/mn){{/is_warning}}" + message = coalesce(var.uploaded_bytes_message, var.message) + type = "query alert" + + query = < ${var.uploaded_bytes_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.uploaded_bytes_threshold_warning + critical = var.uploaded_bytes_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + include_tags = true + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:big-query", "team:claranet", "created-by:terraform"], var.uploaded_bytes_extra_tags) +} + +# +# Uploaded Bytes Billed +# +resource "datadog_monitor" "uploaded_bytes_billed" { + count = var.uploaded_bytes_billed_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP Big Query Uploaded Bytes Billed {{#is_alert}}{{{comparator}}} {{threshold}}B/mn ({{value}}B/mn){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}B/mn ({{value}}B/mn){{/is_warning}}" + message = coalesce(var.uploaded_bytes_billed_message, var.message) + type = "query alert" + + query = < ${var.uploaded_bytes_billed_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.uploaded_bytes_billed_threshold_warning + critical = var.uploaded_bytes_billed_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + include_tags = true + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:big-query", "team:claranet", "created-by:terraform"], var.uploaded_bytes_billed_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/big-query/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/big-query/outputs.tf new file mode 100755 index 0000000..f3153bf --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/big-query/outputs.tf @@ -0,0 +1,45 @@ +output "available_slots_id" { + description = "id for monitor available_slots" + value = datadog_monitor.available_slots.*.id +} + +output "concurrent_queries_id" { + description = "id for monitor concurrent_queries" + value = datadog_monitor.concurrent_queries.*.id +} + +output "execution_time_id" { + description = "id for monitor execution_time" + value = datadog_monitor.execution_time.*.id +} + +output "scanned_bytes_id" { + description = "id for monitor scanned_bytes" + value = datadog_monitor.scanned_bytes.*.id +} + +output "scanned_bytes_billed_id" { + description = "id for monitor scanned_bytes_billed" + value = datadog_monitor.scanned_bytes_billed.*.id +} + +output "stored_bytes_id" { + description = "id for monitor stored_bytes" + value = datadog_monitor.stored_bytes.*.id +} + +output "table_count_id" { + description = "id for monitor table_count" + value = datadog_monitor.table_count.*.id +} + +output "uploaded_bytes_id" { + description = "id for monitor uploaded_bytes" + value = datadog_monitor.uploaded_bytes.*.id +} + +output "uploaded_bytes_billed_id" { + description = "id for monitor uploaded_bytes_billed" + value = datadog_monitor.uploaded_bytes_billed.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/big-query/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/big-query/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/big-query/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/common/MANIFEST.txt b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/common/MANIFEST.txt new file mode 100755 index 0000000..6de6b50 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/common/MANIFEST.txt @@ -0,0 +1 @@ +cloud-gcp diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/common/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/common/README.md new file mode 100755 index 0000000..20830dc --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/common/README.md @@ -0,0 +1,135 @@ +# CLOUD GCP CLOUD-SQL COMMON DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-gcp-cloud-sql-common" { + source = "claranet/monitors/datadog//cloud/gcp/cloud-sql/common" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Cloud SQL CPU Utilization +- Cloud SQL Disk Utilization +- Cloud SQL Disk Utilization forecast +- Cloud SQL Failover Unavailable +- Cloud SQL Memory Utilization +- Cloud SQL Memory Utilization forecast (disabled by default) + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cpu_utilization](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.disk_utilization](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.disk_utilization_forecast](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.failover_unavailable](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.memory_utilization](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.memory_utilization_forecast](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_utilization\_enabled](#input\_cpu\_utilization\_enabled) | Flag to enable GCP Cloud SQL CPU Utilization monitor | `string` | `"true"` | no | +| [cpu\_utilization\_extra\_tags](#input\_cpu\_utilization\_extra\_tags) | Extra tags for GCP Cloud SQL CPU Utilization monitor | `list(string)` | `[]` | no | +| [cpu\_utilization\_message](#input\_cpu\_utilization\_message) | Custom message for the CPU Utilization monitor | `string` | `""` | no | +| [cpu\_utilization\_threshold\_critical](#input\_cpu\_utilization\_threshold\_critical) | CPU Utilization in percentage (critical threshold) | `string` | `90` | no | +| [cpu\_utilization\_threshold\_warning](#input\_cpu\_utilization\_threshold\_warning) | CPU Utilization in percentage (warning threshold) | `string` | `80` | no | +| [cpu\_utilization\_time\_aggregator](#input\_cpu\_utilization\_time\_aggregator) | Time aggregator for the CPU Utilization monitor | `string` | `"avg"` | no | +| [cpu\_utilization\_timeframe](#input\_cpu\_utilization\_timeframe) | Timeframe for the CPU Utilization monitor | `string` | `"last_15m"` | no | +| [disk\_utilization\_enabled](#input\_disk\_utilization\_enabled) | Flag to enable GCP Cloud SQL Disk Utilization monitor | `string` | `"true"` | no | +| [disk\_utilization\_extra\_tags](#input\_disk\_utilization\_extra\_tags) | Extra tags for GCP Cloud SQL CPU Utilization monitor | `list(string)` | `[]` | no | +| [disk\_utilization\_forecast\_algorithm](#input\_disk\_utilization\_forecast\_algorithm) | Algorithm for the Disk Utilization Forecast monitor | `string` | `"linear"` | no | +| [disk\_utilization\_forecast\_deviations](#input\_disk\_utilization\_forecast\_deviations) | Deviations for the Disk Utilization Forecast monitor | `string` | `1` | no | +| [disk\_utilization\_forecast\_enabled](#input\_disk\_utilization\_forecast\_enabled) | Flag to enable GCP Cloud SQL Disk Utilization Forecast monitor | `string` | `"true"` | no | +| [disk\_utilization\_forecast\_extra\_tags](#input\_disk\_utilization\_forecast\_extra\_tags) | Extra tags for GCP Cloud SQL Disk Utilization Forecast monitor | `list(string)` | `[]` | no | +| [disk\_utilization\_forecast\_interval](#input\_disk\_utilization\_forecast\_interval) | Interval for the Disk Utilization Forecast monitor | `string` | `"60m"` | no | +| [disk\_utilization\_forecast\_linear\_history](#input\_disk\_utilization\_forecast\_linear\_history) | History for the Disk Utilization Forecast monitor | `string` | `"3d"` | no | +| [disk\_utilization\_forecast\_linear\_model](#input\_disk\_utilization\_forecast\_linear\_model) | Model for the Disk Utilization Forecast monitor | `string` | `"default"` | no | +| [disk\_utilization\_forecast\_message](#input\_disk\_utilization\_forecast\_message) | Custom message for the Disk Utilization Forecast monitor | `string` | `""` | no | +| [disk\_utilization\_forecast\_seasonal\_seasonality](#input\_disk\_utilization\_forecast\_seasonal\_seasonality) | Seasonality for the Disk Utilization Forecast monitor | `string` | `"weekly"` | no | +| [disk\_utilization\_forecast\_threshold\_critical](#input\_disk\_utilization\_forecast\_threshold\_critical) | Disk Utilization Forecast in percentage (critical threshold) | `string` | `80` | no | +| [disk\_utilization\_forecast\_threshold\_critical\_recovery](#input\_disk\_utilization\_forecast\_threshold\_critical\_recovery) | Disk Utilization Forecast in percentage (recovery threshold) | `string` | `72` | no | +| [disk\_utilization\_forecast\_time\_aggregator](#input\_disk\_utilization\_forecast\_time\_aggregator) | Time aggregator for the Disk Utilization Forecast monitor | `string` | `"max"` | no | +| [disk\_utilization\_forecast\_timeframe](#input\_disk\_utilization\_forecast\_timeframe) | Timeframe for the Disk Utilization Forecast monitor | `string` | `"next_1w"` | no | +| [disk\_utilization\_message](#input\_disk\_utilization\_message) | Custom message for the Disk Utilization monitor | `string` | `""` | no | +| [disk\_utilization\_no\_data\_timeframe](#input\_disk\_utilization\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [disk\_utilization\_threshold\_critical](#input\_disk\_utilization\_threshold\_critical) | Disk Utilization in percentage (critical threshold) | `string` | `90` | no | +| [disk\_utilization\_threshold\_warning](#input\_disk\_utilization\_threshold\_warning) | Disk Utilization in percentage (warning threshold) | `string` | `80` | no | +| [disk\_utilization\_time\_aggregator](#input\_disk\_utilization\_time\_aggregator) | Time aggregator for the Disk Utilization monitor | `string` | `"avg"` | no | +| [disk\_utilization\_timeframe](#input\_disk\_utilization\_timeframe) | Timeframe for the Disk Utilization monitor | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [failover\_unavailable\_enabled](#input\_failover\_unavailable\_enabled) | Flag to enable GCP Cloud SQL Failover Unavailable monitor | `string` | `"true"` | no | +| [failover\_unavailable\_extra\_tags](#input\_failover\_unavailable\_extra\_tags) | Extra tags for GCP Cloud SQL Failover Unavailable monitor | `list(string)` | `[]` | no | +| [failover\_unavailable\_message](#input\_failover\_unavailable\_message) | Custom message for the Failover Unavailable monitor | `string` | `""` | no | +| [failover\_unavailable\_threshold\_critical](#input\_failover\_unavailable\_threshold\_critical) | Failover Unavailable critical threshold | `string` | `0` | no | +| [failover\_unavailable\_time\_aggregator](#input\_failover\_unavailable\_time\_aggregator) | Time aggreggator for the Failover Unavailable monitor | `string` | `"max"` | no | +| [failover\_unavailable\_timeframe](#input\_failover\_unavailable\_timeframe) | Timeframe for the Failover Unavailable monitor | `string` | `"last_10m"` | no | +| [filter\_tags](#input\_filter\_tags) | Tags used for filtering | `string` | `"*"` | no | +| [filter\_tags\_failover\_unavailable](#input\_filter\_tags\_failover\_unavailable) | Tags used for filtering specific to the failover unavailable monitor which is only useful for master instances | `string` | `""` | no | +| [memory\_utilization\_enabled](#input\_memory\_utilization\_enabled) | Flag to enable GCP Cloud SQL Memory Utilization monitor | `string` | `"true"` | no | +| [memory\_utilization\_extra\_tags](#input\_memory\_utilization\_extra\_tags) | Extra tags for GCP Cloud SQL Memory Utilization monitor | `list(string)` | `[]` | no | +| [memory\_utilization\_forecast\_algorithm](#input\_memory\_utilization\_forecast\_algorithm) | Algorithm for the Memory Utilization Forecast monitor | `string` | `"linear"` | no | +| [memory\_utilization\_forecast\_deviations](#input\_memory\_utilization\_forecast\_deviations) | Deviations for the Memory Utilization Forecast monitor | `string` | `1` | no | +| [memory\_utilization\_forecast\_enabled](#input\_memory\_utilization\_forecast\_enabled) | Flag to enable GCP Cloud SQL Memory Utilization Forecast monitor | `string` | `"false"` | no | +| [memory\_utilization\_forecast\_extra\_tags](#input\_memory\_utilization\_forecast\_extra\_tags) | Extra tags for GCP Cloud SQL Memory Utilization Forecast monitor | `list(string)` | `[]` | no | +| [memory\_utilization\_forecast\_interval](#input\_memory\_utilization\_forecast\_interval) | Interval for the Memory Utilization Forecast monitor | `string` | `"30m"` | no | +| [memory\_utilization\_forecast\_linear\_history](#input\_memory\_utilization\_forecast\_linear\_history) | History for the Memory Utilization Forecast monitor | `string` | `"12h"` | no | +| [memory\_utilization\_forecast\_linear\_model](#input\_memory\_utilization\_forecast\_linear\_model) | Model for the Memory Utilization Forecast monitor | `string` | `"default"` | no | +| [memory\_utilization\_forecast\_message](#input\_memory\_utilization\_forecast\_message) | Custom message for the Memory Utilization Forecast monitor | `string` | `""` | no | +| [memory\_utilization\_forecast\_seasonal\_seasonality](#input\_memory\_utilization\_forecast\_seasonal\_seasonality) | Seasonality for the Memory Utilization Forecast monitor | `string` | `"weekly"` | no | +| [memory\_utilization\_forecast\_threshold\_critical](#input\_memory\_utilization\_forecast\_threshold\_critical) | Memory Utilization Forecast in percentage (warning threshold) | `number` | `90` | no | +| [memory\_utilization\_forecast\_threshold\_critical\_recovery](#input\_memory\_utilization\_forecast\_threshold\_critical\_recovery) | Memory Utilization Forecast in percentage (recovery threshold) | `number` | `81` | no | +| [memory\_utilization\_forecast\_time\_aggregator](#input\_memory\_utilization\_forecast\_time\_aggregator) | Time aggregator for the Memory Utilization Forecast monitor | `string` | `"max"` | no | +| [memory\_utilization\_forecast\_timeframe](#input\_memory\_utilization\_forecast\_timeframe) | Timeframe for the Memory Utilization Forecast monitor | `string` | `"next_3d"` | no | +| [memory\_utilization\_message](#input\_memory\_utilization\_message) | Custom message for the Memory Utilization monitor | `string` | `""` | no | +| [memory\_utilization\_threshold\_critical](#input\_memory\_utilization\_threshold\_critical) | Memory Utilization in percentage (critical threshold) | `number` | `90` | no | +| [memory\_utilization\_threshold\_warning](#input\_memory\_utilization\_threshold\_warning) | Memory Utilization in percentage (warning threshold) | `number` | `80` | no | +| [memory\_utilization\_time\_aggregator](#input\_memory\_utilization\_time\_aggregator) | Time aggregator for the Memory Utilization monitor | `string` | `"avg"` | no | +| [memory\_utilization\_timeframe](#input\_memory\_utilization\_timeframe) | Timeframe for the Memory Utilization monitor | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the new host evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cpu\_utilization\_id](#output\_cpu\_utilization\_id) | id for monitor cpu\_utilization | +| [disk\_utilization\_forecast\_id](#output\_disk\_utilization\_forecast\_id) | id for monitor disk\_utilization\_forecast | +| [disk\_utilization\_id](#output\_disk\_utilization\_id) | id for monitor disk\_utilization | +| [failover\_unavailable\_id](#output\_failover\_unavailable\_id) | id for monitor failover\_unavailable | +| [memory\_utilization\_forecast\_id](#output\_memory\_utilization\_forecast\_id) | id for monitor memory\_utilization\_forecast | +| [memory\_utilization\_id](#output\_memory\_utilization\_id) | id for monitor memory\_utilization | +## Related documentation + +* [GCP Metrics for CloudSQL](https://cloud.google.com/monitoring/api/metrics_gcp#gcp-cloudsql) +* [Datadog Useful monitors for GCP CloudSQL](https://www.datadoghq.com/blog/monitor-google-cloud-sql/) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/common/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/common/inputs.tf new file mode 100755 index 0000000..6063dce --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/common/inputs.tf @@ -0,0 +1,380 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags" { + description = "Tags used for filtering" + default = "*" +} + +variable "filter_tags_failover_unavailable" { + description = "Tags used for filtering specific to the failover unavailable monitor which is only useful for master instances" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds for the new host evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "disk_utilization_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# +# CPU +# + +variable "cpu_utilization_message" { + description = "Custom message for the CPU Utilization monitor" + type = string + default = "" +} + +variable "cpu_utilization_time_aggregator" { + description = "Time aggregator for the CPU Utilization monitor" + type = string + default = "avg" +} + +variable "cpu_utilization_timeframe" { + description = "Timeframe for the CPU Utilization monitor" + type = string + default = "last_15m" +} + +variable "cpu_utilization_threshold_warning" { + description = "CPU Utilization in percentage (warning threshold)" + type = string + default = 80 +} + +variable "cpu_utilization_threshold_critical" { + description = "CPU Utilization in percentage (critical threshold)" + type = string + default = 90 +} + +variable "cpu_utilization_enabled" { + description = "Flag to enable GCP Cloud SQL CPU Utilization monitor" + type = string + default = "true" +} + +variable "cpu_utilization_extra_tags" { + description = "Extra tags for GCP Cloud SQL CPU Utilization monitor" + type = list(string) + default = [] +} + +# +# DISK Utilization +# + +variable "disk_utilization_message" { + description = "Custom message for the Disk Utilization monitor" + type = string + default = "" +} + +variable "disk_utilization_time_aggregator" { + description = "Time aggregator for the Disk Utilization monitor" + type = string + default = "avg" +} + +variable "disk_utilization_timeframe" { + description = "Timeframe for the Disk Utilization monitor" + type = string + default = "last_5m" +} + +variable "disk_utilization_threshold_warning" { + description = "Disk Utilization in percentage (warning threshold)" + type = string + default = 80 +} + +variable "disk_utilization_threshold_critical" { + description = "Disk Utilization in percentage (critical threshold)" + type = string + default = 90 +} + +variable "disk_utilization_enabled" { + description = "Flag to enable GCP Cloud SQL Disk Utilization monitor" + type = string + default = "true" +} + +variable "disk_utilization_extra_tags" { + description = "Extra tags for GCP Cloud SQL CPU Utilization monitor" + type = list(string) + default = [] +} + +# +# DISK Utilization Forecast +# + +variable "disk_utilization_forecast_message" { + description = "Custom message for the Disk Utilization Forecast monitor" + type = string + default = "" +} + +variable "disk_utilization_forecast_time_aggregator" { + description = "Time aggregator for the Disk Utilization Forecast monitor" + type = string + default = "max" +} + +variable "disk_utilization_forecast_timeframe" { + description = "Timeframe for the Disk Utilization Forecast monitor" + type = string + default = "next_1w" +} + +variable "disk_utilization_forecast_algorithm" { + description = "Algorithm for the Disk Utilization Forecast monitor" + type = string + default = "linear" +} + +variable "disk_utilization_forecast_deviations" { + description = "Deviations for the Disk Utilization Forecast monitor" + type = string + default = 1 +} + +variable "disk_utilization_forecast_interval" { + description = "Interval for the Disk Utilization Forecast monitor" + type = string + default = "60m" +} + +variable "disk_utilization_forecast_linear_history" { + description = "History for the Disk Utilization Forecast monitor" + type = string + default = "3d" +} + +variable "disk_utilization_forecast_linear_model" { + description = "Model for the Disk Utilization Forecast monitor" + type = string + default = "default" +} + +variable "disk_utilization_forecast_seasonal_seasonality" { + description = "Seasonality for the Disk Utilization Forecast monitor" + type = string + default = "weekly" +} + +variable "disk_utilization_forecast_threshold_critical" { + description = "Disk Utilization Forecast in percentage (critical threshold)" + type = string + default = 80 +} + +variable "disk_utilization_forecast_threshold_critical_recovery" { + description = "Disk Utilization Forecast in percentage (recovery threshold)" + type = string + default = 72 +} + +variable "disk_utilization_forecast_enabled" { + description = "Flag to enable GCP Cloud SQL Disk Utilization Forecast monitor" + type = string + default = "true" +} + +variable "disk_utilization_forecast_extra_tags" { + description = "Extra tags for GCP Cloud SQL Disk Utilization Forecast monitor" + type = list(string) + default = [] +} + +# +# Memory Utilization +# + +variable "memory_utilization_message" { + description = "Custom message for the Memory Utilization monitor" + default = "" +} + +variable "memory_utilization_time_aggregator" { + description = "Time aggregator for the Memory Utilization monitor" + default = "avg" +} + +variable "memory_utilization_timeframe" { + description = "Timeframe for the Memory Utilization monitor" + default = "last_5m" +} + +variable "memory_utilization_threshold_warning" { + description = "Memory Utilization in percentage (warning threshold)" + default = 80 +} + +variable "memory_utilization_threshold_critical" { + description = "Memory Utilization in percentage (critical threshold)" + default = 90 +} + +variable "memory_utilization_enabled" { + description = "Flag to enable GCP Cloud SQL Memory Utilization monitor" + type = string + default = "true" +} + +variable "memory_utilization_extra_tags" { + description = "Extra tags for GCP Cloud SQL Memory Utilization monitor" + type = list(string) + default = [] +} + +# +# Memory Utilization Forecast +# + +variable "memory_utilization_forecast_message" { + description = "Custom message for the Memory Utilization Forecast monitor" + default = "" +} + +variable "memory_utilization_forecast_time_aggregator" { + description = "Time aggregator for the Memory Utilization Forecast monitor" + default = "max" +} + +variable "memory_utilization_forecast_timeframe" { + description = "Timeframe for the Memory Utilization Forecast monitor" + default = "next_3d" +} + +variable "memory_utilization_forecast_algorithm" { + description = "Algorithm for the Memory Utilization Forecast monitor" + type = string + default = "linear" +} + +variable "memory_utilization_forecast_deviations" { + description = "Deviations for the Memory Utilization Forecast monitor" + type = string + default = 1 +} + +variable "memory_utilization_forecast_interval" { + description = "Interval for the Memory Utilization Forecast monitor" + type = string + default = "30m" +} + +variable "memory_utilization_forecast_linear_history" { + description = "History for the Memory Utilization Forecast monitor" + type = string + default = "12h" +} + +variable "memory_utilization_forecast_linear_model" { + description = "Model for the Memory Utilization Forecast monitor" + type = string + default = "default" +} + +variable "memory_utilization_forecast_seasonal_seasonality" { + description = "Seasonality for the Memory Utilization Forecast monitor" + type = string + default = "weekly" +} + +variable "memory_utilization_forecast_threshold_critical" { + description = "Memory Utilization Forecast in percentage (warning threshold)" + default = 90 +} + +variable "memory_utilization_forecast_threshold_critical_recovery" { + description = "Memory Utilization Forecast in percentage (recovery threshold)" + default = 81 +} + +variable "memory_utilization_forecast_enabled" { + description = "Flag to enable GCP Cloud SQL Memory Utilization Forecast monitor" + type = string + default = "false" +} + +variable "memory_utilization_forecast_extra_tags" { + description = "Extra tags for GCP Cloud SQL Memory Utilization Forecast monitor" + type = list(string) + default = [] +} + +# +# Failover Unavailable +# + +variable "failover_unavailable_message" { + description = "Custom message for the Failover Unavailable monitor" + type = string + default = "" +} + +variable "failover_unavailable_time_aggregator" { + description = "Time aggreggator for the Failover Unavailable monitor" + type = string + default = "max" +} + +variable "failover_unavailable_timeframe" { + description = "Timeframe for the Failover Unavailable monitor" + type = string + default = "last_10m" +} + +variable "failover_unavailable_threshold_critical" { + description = "Failover Unavailable critical threshold" + type = string + default = 0 +} + +variable "failover_unavailable_enabled" { + description = "Flag to enable GCP Cloud SQL Failover Unavailable monitor" + type = string + default = "true" +} + +variable "failover_unavailable_extra_tags" { + description = "Extra tags for GCP Cloud SQL Failover Unavailable monitor" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/common/monitors-cloud-sql-common.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/common/monitors-cloud-sql-common.tf new file mode 100755 index 0000000..66c2cac --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/common/monitors-cloud-sql-common.tf @@ -0,0 +1,212 @@ +# +# CPU Utilization +# +resource "datadog_monitor" "cpu_utilization" { + count = var.cpu_utilization_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Cloud SQL CPU Utilization {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cpu_utilization_message, var.message) + type = "query alert" + + query = < ${var.cpu_utilization_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.cpu_utilization_threshold_warning + critical = var.cpu_utilization_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:cloud-sql", "team:claranet", "created-by:terraform"], var.cpu_utilization_extra_tags) +} + +# +# Disk Utilization +# +resource "datadog_monitor" "disk_utilization" { + count = var.disk_utilization_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Cloud SQL Disk Utilization {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.disk_utilization_message, var.message) + type = "query alert" + + query = < ${var.disk_utilization_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.disk_utilization_threshold_warning + critical = var.disk_utilization_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = var.notify_no_data + no_data_timeframe = var.disk_utilization_no_data_timeframe + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:cloud-sql", "team:claranet", "created-by:terraform"], var.disk_utilization_extra_tags) +} + +# +# Disk Utilization Forecast +# +resource "datadog_monitor" "disk_utilization_forecast" { + count = var.disk_utilization_forecast_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Cloud SQL Disk Utilization could reach {{#is_alert}}{{threshold}}%%{{/is_alert}} in a near future" + message = coalesce(var.disk_utilization_forecast_message, var.message) + type = "query alert" + + query = <= ${var.disk_utilization_forecast_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.disk_utilization_forecast_threshold_critical + critical_recovery = var.disk_utilization_forecast_threshold_critical_recovery + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:cloud-sql", "team:claranet", "created-by:terraform"], var.disk_utilization_forecast_extra_tags) +} + +# +# Memory Utilization +# +resource "datadog_monitor" "memory_utilization" { + count = var.memory_utilization_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Cloud SQL Memory Utilization {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.memory_utilization_message, var.message) + type = "query alert" + + query = < ${var.memory_utilization_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.memory_utilization_threshold_warning + critical = var.memory_utilization_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:cloud-sql", "team:claranet", "created-by:terraform"], var.memory_utilization_extra_tags) +} + +# +# Memory Utilization Forecast +# +resource "datadog_monitor" "memory_utilization_forecast" { + count = var.memory_utilization_forecast_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Cloud SQL Memory Utilization could reach {{#is_alert}}{{threshold}}%%{{/is_alert}} in a near future" + message = coalesce(var.memory_utilization_forecast_message, var.message) + type = "query alert" + + query = <= ${var.memory_utilization_forecast_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.memory_utilization_forecast_threshold_critical + critical_recovery = var.memory_utilization_forecast_threshold_critical_recovery + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:cloud-sql", "team:claranet", "created-by:terraform"], var.memory_utilization_forecast_extra_tags) +} + +# +# Failover Unavailable +# +resource "datadog_monitor" "failover_unavailable" { + count = var.failover_unavailable_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Cloud SQL Failover Unavailable" + message = coalesce(var.failover_unavailable_message, var.message) + type = "metric alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.replication_lag](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags](#input\_filter\_tags) | Tags used for filtering | `string` | `"*"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the new host evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [replication\_lag\_enabled](#input\_replication\_lag\_enabled) | Flag to enable GCP Cloud SQL Replication Lag monitor | `string` | `"true"` | no | +| [replication\_lag\_extra\_tags](#input\_replication\_lag\_extra\_tags) | Extra tags for GCP Cloud SQL SQL Replication monitor | `list(string)` | `[]` | no | +| [replication\_lag\_message](#input\_replication\_lag\_message) | Custom message for the Replication Lag monitor | `string` | `""` | no | +| [replication\_lag\_no\_data\_timeframe](#input\_replication\_lag\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `20` | no | +| [replication\_lag\_threshold\_critical](#input\_replication\_lag\_threshold\_critical) | Seconds behind the master (critical threshold) | `string` | `180` | no | +| [replication\_lag\_threshold\_warning](#input\_replication\_lag\_threshold\_warning) | Seconds behind the master (warning threshold) | `string` | `90` | no | +| [replication\_lag\_time\_aggregator](#input\_replication\_lag\_time\_aggregator) | Time aggregator for the Replication Lag monitor | `string` | `"min"` | no | +| [replication\_lag\_timeframe](#input\_replication\_lag\_timeframe) | Timeframe for the Replication Lag monitor | `string` | `"last_10m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [replication\_lag\_id](#output\_replication\_lag\_id) | id for monitor replication\_lag | +## Related documentation + +* [GCP Metrics for CloudSQL](https://cloud.google.com/monitoring/api/metrics_gcp#gcp-cloudsql) +* [Datadog Useful monitors for GCP CloudSQL](https://www.datadoghq.com/blog/monitor-google-cloud-sql/) +* [Max connections depends on the type of the instance](https://cloud.google.com/sql/docs/quotas#fixed-limits) +* [Monitoring Replication Lag](https://cloud.google.com/sql/docs/mysql/high-availability#replication-lag-monitor) +* [Monitoring MySQL Performance Metrics](https://www.datadoghq.com/blog/monitoring-mysql-performance-metrics) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/mysql/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/mysql/inputs.tf new file mode 100755 index 0000000..65cdb43 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/mysql/inputs.tf @@ -0,0 +1,89 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags" { + description = "Tags used for filtering" + default = "*" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds for the new host evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "replication_lag_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 20 +} + +# +# Replication Lag +# + +variable "replication_lag_message" { + description = "Custom message for the Replication Lag monitor" + type = string + default = "" +} + +variable "replication_lag_time_aggregator" { + description = "Time aggregator for the Replication Lag monitor" + type = string + default = "min" +} + +variable "replication_lag_timeframe" { + description = "Timeframe for the Replication Lag monitor" + type = string + default = "last_10m" +} + +variable "replication_lag_threshold_warning" { + description = "Seconds behind the master (warning threshold)" + type = string + default = 90 +} + +variable "replication_lag_threshold_critical" { + description = "Seconds behind the master (critical threshold)" + type = string + default = 180 +} + +variable "replication_lag_enabled" { + description = "Flag to enable GCP Cloud SQL Replication Lag monitor" + type = string + default = "true" +} + +variable "replication_lag_extra_tags" { + description = "Extra tags for GCP Cloud SQL SQL Replication monitor" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/mysql/monitors-cloudsql-mysql.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/mysql/monitors-cloudsql-mysql.tf new file mode 100755 index 0000000..dfa1fcc --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/mysql/monitors-cloudsql-mysql.tf @@ -0,0 +1,34 @@ +# +# Replication Lag +# +resource "datadog_monitor" "replication_lag" { + count = var.replication_lag_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Cloud SQL MySQL Replication Lag {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + message = coalesce(var.replication_lag_message, var.message) + type = "metric alert" + + query = < ${var.replication_lag_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.replication_lag_threshold_critical + warning = var.replication_lag_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = var.notify_no_data + no_data_timeframe = var.replication_lag_no_data_timeframe + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:cloud-sql", "team:claranet", "created-by:terraform", "engine:mysql"], var.replication_lag_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/mysql/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/mysql/outputs.tf new file mode 100755 index 0000000..3134033 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/mysql/outputs.tf @@ -0,0 +1,5 @@ +output "replication_lag_id" { + description = "id for monitor replication_lag" + value = datadog_monitor.replication_lag.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/mysql/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/mysql/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/cloud-sql/mysql/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/gce/instance/MANIFEST.txt b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/gce/instance/MANIFEST.txt new file mode 100755 index 0000000..6de6b50 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/gce/instance/MANIFEST.txt @@ -0,0 +1 @@ +cloud-gcp diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/gce/instance/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/gce/instance/README.md new file mode 100755 index 0000000..45e4112 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/gce/instance/README.md @@ -0,0 +1,93 @@ +# CLOUD GCP GCE INSTANCE DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-gcp-gce-instance" { + source = "claranet/monitors/datadog//cloud/gcp/gce/instance" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Compute Engine instance CPU Utilization +- Compute Engine instance Disk Throttled Bps +- Compute Engine instance Disk Throttled OPS + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cpu_utilization](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.disk_throttled_bps](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.disk_throttled_ops](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_utilization\_enabled](#input\_cpu\_utilization\_enabled) | Flag to enable CPU Utilization monitor | `string` | `"true"` | no | +| [cpu\_utilization\_extra\_tags](#input\_cpu\_utilization\_extra\_tags) | Extra tags for CPU Utilization monitor | `list(string)` | `[]` | no | +| [cpu\_utilization\_message](#input\_cpu\_utilization\_message) | Custom message for the CPU Utilization monitor | `string` | `""` | no | +| [cpu\_utilization\_no\_data\_timeframe](#input\_cpu\_utilization\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `30` | no | +| [cpu\_utilization\_threshold\_critical](#input\_cpu\_utilization\_threshold\_critical) | CPU Utilization in percentage (critical threshold) | `string` | `90` | no | +| [cpu\_utilization\_threshold\_warning](#input\_cpu\_utilization\_threshold\_warning) | CPU Utilization in percentage (warning threshold) | `string` | `80` | no | +| [cpu\_utilization\_time\_aggregator](#input\_cpu\_utilization\_time\_aggregator) | Time aggregator for the CPU Utilization monitor | `string` | `"avg"` | no | +| [cpu\_utilization\_timeframe](#input\_cpu\_utilization\_timeframe) | Timeframe for the CPU Utilization monitor | `string` | `"last_15m"` | no | +| [disk\_throttled\_bps\_enabled](#input\_disk\_throttled\_bps\_enabled) | Flag to enable Disk Throttled Bps monitor | `string` | `"true"` | no | +| [disk\_throttled\_bps\_extra\_tags](#input\_disk\_throttled\_bps\_extra\_tags) | Extra tags for Disk Throttled Bps monitor | `list(string)` | `[]` | no | +| [disk\_throttled\_bps\_message](#input\_disk\_throttled\_bps\_message) | Custom message for the Disk Throttled Bps monitor | `string` | `""` | no | +| [disk\_throttled\_bps\_threshold\_critical](#input\_disk\_throttled\_bps\_threshold\_critical) | Disk Throttled Bps in percentage (critical threshold) | `string` | `50` | no | +| [disk\_throttled\_bps\_threshold\_warning](#input\_disk\_throttled\_bps\_threshold\_warning) | Disk Throttled Bps in percentage (warning threshold) | `string` | `30` | no | +| [disk\_throttled\_bps\_time\_aggregator](#input\_disk\_throttled\_bps\_time\_aggregator) | Time aggregator for the Disk Throttled Bps monitor | `string` | `"min"` | no | +| [disk\_throttled\_bps\_timeframe](#input\_disk\_throttled\_bps\_timeframe) | Timeframe for the Disk Throttled Bps monitor | `string` | `"last_15m"` | no | +| [disk\_throttled\_ops\_enabled](#input\_disk\_throttled\_ops\_enabled) | Flag to enable Disk Throttled OPS monitor | `string` | `"true"` | no | +| [disk\_throttled\_ops\_extra\_tags](#input\_disk\_throttled\_ops\_extra\_tags) | Extra tags for Disk Throttled OPS monitor | `list(string)` | `[]` | no | +| [disk\_throttled\_ops\_message](#input\_disk\_throttled\_ops\_message) | Custom message for the Disk Throttled OPS monitor | `string` | `""` | no | +| [disk\_throttled\_ops\_threshold\_critical](#input\_disk\_throttled\_ops\_threshold\_critical) | Disk Throttled OPS in percentage (critical threshold) | `string` | `50` | no | +| [disk\_throttled\_ops\_threshold\_warning](#input\_disk\_throttled\_ops\_threshold\_warning) | Disk Throttled OPS in percentage (warning threshold) | `string` | `30` | no | +| [disk\_throttled\_ops\_time\_aggregator](#input\_disk\_throttled\_ops\_time\_aggregator) | Time aggregator for the Disk Throttled OPS monitor | `string` | `"min"` | no | +| [disk\_throttled\_ops\_timeframe](#input\_disk\_throttled\_ops\_timeframe) | Timeframe for the Disk Throttled OPS monitor | `string` | `"last_15m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags](#input\_filter\_tags) | Tags used for filtering | `string` | `"*"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the new host evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cpu\_utilization\_id](#output\_cpu\_utilization\_id) | id for monitor cpu\_utilization | +| [disk\_throttled\_bps\_id](#output\_disk\_throttled\_bps\_id) | id for monitor disk\_throttled\_bps | +| [disk\_throttled\_ops\_id](#output\_disk\_throttled\_ops\_id) | id for monitor disk\_throttled\_ops | +## Related documentation + +* [Datadog GCE Instance metrics](https://www.datadoghq.com/blog/monitoring-google-compute-engine-performance/#instance-metrics) +* [GCP Maximum OPS and Bps by device type and size](https://cloud.google.com/compute/docs/disks/) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/gce/instance/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/gce/instance/inputs.tf new file mode 100755 index 0000000..893db24 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/gce/instance/inputs.tf @@ -0,0 +1,181 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags" { + description = "Tags used for filtering" + default = "*" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds for the new host evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "cpu_utilization_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 30 +} + +# +# CPU +# + +variable "cpu_utilization_message" { + description = "Custom message for the CPU Utilization monitor" + type = string + default = "" +} + +variable "cpu_utilization_time_aggregator" { + description = "Time aggregator for the CPU Utilization monitor" + type = string + default = "avg" +} + +variable "cpu_utilization_timeframe" { + description = "Timeframe for the CPU Utilization monitor" + type = string + default = "last_15m" +} + +variable "cpu_utilization_threshold_warning" { + description = "CPU Utilization in percentage (warning threshold)" + type = string + default = 80 +} + +variable "cpu_utilization_threshold_critical" { + description = "CPU Utilization in percentage (critical threshold)" + type = string + default = 90 +} + +variable "cpu_utilization_enabled" { + description = "Flag to enable CPU Utilization monitor" + type = string + default = "true" +} + +variable "cpu_utilization_extra_tags" { + description = "Extra tags for CPU Utilization monitor" + type = list(string) + default = [] +} + +# +# Disk Throttled Bps +# + +variable "disk_throttled_bps_message" { + description = "Custom message for the Disk Throttled Bps monitor" + type = string + default = "" +} + +variable "disk_throttled_bps_time_aggregator" { + description = "Time aggregator for the Disk Throttled Bps monitor" + type = string + default = "min" +} + +variable "disk_throttled_bps_timeframe" { + description = "Timeframe for the Disk Throttled Bps monitor" + type = string + default = "last_15m" +} + +variable "disk_throttled_bps_threshold_warning" { + description = "Disk Throttled Bps in percentage (warning threshold)" + type = string + default = 30 +} + +variable "disk_throttled_bps_threshold_critical" { + description = "Disk Throttled Bps in percentage (critical threshold)" + type = string + default = 50 +} + +variable "disk_throttled_bps_enabled" { + description = "Flag to enable Disk Throttled Bps monitor" + type = string + default = "true" +} + +variable "disk_throttled_bps_extra_tags" { + description = "Extra tags for Disk Throttled Bps monitor" + type = list(string) + default = [] +} + +# +# Disk Throttled OPS +# + +variable "disk_throttled_ops_message" { + description = "Custom message for the Disk Throttled OPS monitor" + type = string + default = "" +} + +variable "disk_throttled_ops_time_aggregator" { + description = "Time aggregator for the Disk Throttled OPS monitor" + type = string + default = "min" +} + +variable "disk_throttled_ops_timeframe" { + description = "Timeframe for the Disk Throttled OPS monitor" + type = string + default = "last_15m" +} + +variable "disk_throttled_ops_threshold_warning" { + description = "Disk Throttled OPS in percentage (warning threshold)" + type = string + default = 30 +} + +variable "disk_throttled_ops_threshold_critical" { + description = "Disk Throttled OPS in percentage (critical threshold)" + type = string + default = 50 +} + +variable "disk_throttled_ops_enabled" { + description = "Flag to enable Disk Throttled OPS monitor" + type = string + default = "true" +} + +variable "disk_throttled_ops_extra_tags" { + description = "Extra tags for Disk Throttled OPS monitor" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/gce/instance/monitors-gce-instance.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/gce/instance/monitors-gce-instance.tf new file mode 100755 index 0000000..cf9c721 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/gce/instance/monitors-gce-instance.tf @@ -0,0 +1,112 @@ +# +# CPU Utilization +# +resource "datadog_monitor" "cpu_utilization" { + count = var.cpu_utilization_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Compute Engine instance CPU Utilization {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cpu_utilization_message, var.message) + type = "query alert" + + query = < ${var.cpu_utilization_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.cpu_utilization_threshold_warning + critical = var.cpu_utilization_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = var.notify_no_data + no_data_timeframe = var.cpu_utilization_no_data_timeframe + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:gce-instance", "team:claranet", "created-by:terraform"], var.cpu_utilization_extra_tags) +} + +# +# Disk Throttled Bps +# +resource "datadog_monitor" "disk_throttled_bps" { + count = var.disk_throttled_bps_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Compute Engine instance Disk Throttled Bps {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.disk_throttled_bps_message, var.message) + type = "query alert" + + query = < ${var.disk_throttled_bps_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.disk_throttled_bps_threshold_warning + critical = var.disk_throttled_bps_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:gce-instance", "team:claranet", "created-by:terraform"], var.disk_throttled_bps_extra_tags) +} + +# +# Disk Throttled OPS +# +resource "datadog_monitor" "disk_throttled_ops" { + count = var.disk_throttled_ops_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Compute Engine instance Disk Throttled OPS {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.disk_throttled_ops_message, var.message) + type = "query alert" + + query = < ${var.disk_throttled_ops_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.disk_throttled_ops_threshold_warning + critical = var.disk_throttled_ops_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:gce-instance", "team:claranet", "created-by:terraform"], var.disk_throttled_ops_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/gce/instance/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/gce/instance/outputs.tf new file mode 100755 index 0000000..002b395 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/gce/instance/outputs.tf @@ -0,0 +1,15 @@ +output "cpu_utilization_id" { + description = "id for monitor cpu_utilization" + value = datadog_monitor.cpu_utilization.*.id +} + +output "disk_throttled_bps_id" { + description = "id for monitor disk_throttled_bps" + value = datadog_monitor.disk_throttled_bps.*.id +} + +output "disk_throttled_ops_id" { + description = "id for monitor disk_throttled_ops" + value = datadog_monitor.disk_throttled_ops.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/gce/instance/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/gce/instance/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/gce/instance/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/lb/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/lb/README.md new file mode 100755 index 0000000..1fdd8d5 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/lb/README.md @@ -0,0 +1,115 @@ +# CLOUD GCP LB DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-gcp-lb" { + source = "claranet/monitors/datadog//cloud/gcp/lb" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- GCP LB 4xx errors +- GCP LB 5xx errors +- GCP LB bucket backend latency +- GCP LB Requests count increased abruptly +- GCP LB service backend latency + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.backend_latency_bucket](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.backend_latency_service](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.error_rate_4xx](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.error_rate_5xx](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.request_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [backend\_latency\_bucket\_enabled](#input\_backend\_latency\_bucket\_enabled) | Flag to enable GCP LB Backend Latency monitor | `string` | `"true"` | no | +| [backend\_latency\_bucket\_extra\_tags](#input\_backend\_latency\_bucket\_extra\_tags) | Extra tags for GCP LB Backend Latency monitor | `list(string)` | `[]` | no | +| [backend\_latency\_bucket\_message](#input\_backend\_latency\_bucket\_message) | Custom message for the GCP LB Backend Latency monitor | `string` | `""` | no | +| [backend\_latency\_bucket\_threshold\_critical](#input\_backend\_latency\_bucket\_threshold\_critical) | Latency in milliseconds (critical threshold) | `string` | `8000` | no | +| [backend\_latency\_bucket\_threshold\_warning](#input\_backend\_latency\_bucket\_threshold\_warning) | Latency in milliseconds (warning threshold) | `string` | `4000` | no | +| [backend\_latency\_bucket\_time\_aggregator](#input\_backend\_latency\_bucket\_time\_aggregator) | Timeframe for the GCP LB Backend Latency monitor | `string` | `"min"` | no | +| [backend\_latency\_bucket\_timeframe](#input\_backend\_latency\_bucket\_timeframe) | Timeframe for the GCP LB Backend Latency monitor | `string` | `"last_10m"` | no | +| [backend\_latency\_service\_enabled](#input\_backend\_latency\_service\_enabled) | Flag to enable GCP LB Backend Latency monitor | `string` | `"true"` | no | +| [backend\_latency\_service\_extra\_tags](#input\_backend\_latency\_service\_extra\_tags) | Extra tags for GCP LB Backend Latency monitor | `list(string)` | `[]` | no | +| [backend\_latency\_service\_message](#input\_backend\_latency\_service\_message) | Custom message for the GCP LB Backend Latency monitor | `string` | `""` | no | +| [backend\_latency\_service\_threshold\_critical](#input\_backend\_latency\_service\_threshold\_critical) | Latency in milliseconds (critical threshold) | `string` | `1500` | no | +| [backend\_latency\_service\_threshold\_warning](#input\_backend\_latency\_service\_threshold\_warning) | Latency in milliseconds (warning threshold) | `string` | `1000` | no | +| [backend\_latency\_service\_time\_aggregator](#input\_backend\_latency\_service\_time\_aggregator) | Timeframe for the GCP LB Backend Latency monitor | `string` | `"min"` | no | +| [backend\_latency\_service\_timeframe](#input\_backend\_latency\_service\_timeframe) | Timeframe for the GCP LB Backend Latency monitor | `string` | `"last_10m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [error\_rate\_4xx\_artificial\_request](#input\_error\_rate\_4xx\_artificial\_request) | Divisor Delta for the GCP LB 4XX Errors monitor | `string` | `5` | no | +| [error\_rate\_4xx\_enabled](#input\_error\_rate\_4xx\_enabled) | Flag to enable GCP LB 4XX Errors monitor | `string` | `"true"` | no | +| [error\_rate\_4xx\_extra\_tags](#input\_error\_rate\_4xx\_extra\_tags) | Extra tags for GCP LB 4XX Errors monitor | `list(string)` | `[]` | no | +| [error\_rate\_4xx\_message](#input\_error\_rate\_4xx\_message) | Custom message for the GCP LB 4XX Errors monitor | `string` | `""` | no | +| [error\_rate\_4xx\_threshold\_critical](#input\_error\_rate\_4xx\_threshold\_critical) | Rate error in percentage (critical threshold) | `string` | `60` | no | +| [error\_rate\_4xx\_threshold\_warning](#input\_error\_rate\_4xx\_threshold\_warning) | Rate error in percentage (warning threshold) | `string` | `50` | no | +| [error\_rate\_4xx\_time\_aggregator](#input\_error\_rate\_4xx\_time\_aggregator) | Timeframe for the GCP LB 4XX Errors monitor | `string` | `"min"` | no | +| [error\_rate\_4xx\_timeframe](#input\_error\_rate\_4xx\_timeframe) | Timeframe for the GCP LB 4XX Errors monitor | `string` | `"last_5m"` | no | +| [error\_rate\_5xx\_artificial\_request](#input\_error\_rate\_5xx\_artificial\_request) | Divisor Delta for the GCP LB 5XX Errors monitor | `string` | `5` | no | +| [error\_rate\_5xx\_enabled](#input\_error\_rate\_5xx\_enabled) | Flag to enable GCP LB 5XX Errors monitor | `string` | `"true"` | no | +| [error\_rate\_5xx\_extra\_tags](#input\_error\_rate\_5xx\_extra\_tags) | Extra tags for GCP LB 5XX Errors monitor | `list(string)` | `[]` | no | +| [error\_rate\_5xx\_message](#input\_error\_rate\_5xx\_message) | Custom message for the GCP LB 5XX Errors monitor | `string` | `""` | no | +| [error\_rate\_5xx\_threshold\_critical](#input\_error\_rate\_5xx\_threshold\_critical) | Rate error in percentage (critical threshold) | `string` | `40` | no | +| [error\_rate\_5xx\_threshold\_warning](#input\_error\_rate\_5xx\_threshold\_warning) | Rate error in percentage (warning threshold) | `string` | `30` | no | +| [error\_rate\_5xx\_time\_aggregator](#input\_error\_rate\_5xx\_time\_aggregator) | Timeframe for the GCP LB 5XX Errors monitor | `string` | `"min"` | no | +| [error\_rate\_5xx\_timeframe](#input\_error\_rate\_5xx\_timeframe) | Timeframe for the GCP LB 5XX Errors monitor | `string` | `"last_5m"` | no | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags](#input\_filter\_tags) | Tags used for filtering | `string` | `"*"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the new host evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [request\_count\_enabled](#input\_request\_count\_enabled) | Flag to enable GCP LB Request Count monitor | `string` | `"true"` | no | +| [request\_count\_extra\_tags](#input\_request\_count\_extra\_tags) | Extra tags for GCP LB Request Count monitor | `list(string)` | `[]` | no | +| [request\_count\_message](#input\_request\_count\_message) | Custom message for the GCP LB Request Count monitor | `string` | `""` | no | +| [request\_count\_threshold\_critical](#input\_request\_count\_threshold\_critical) | Desviation in percentage (critical threshold) | `string` | `500` | no | +| [request\_count\_threshold\_warning](#input\_request\_count\_threshold\_warning) | Desviation in percentage (warning threshold) | `string` | `250` | no | +| [request\_count\_time\_aggregator](#input\_request\_count\_time\_aggregator) | Timeframe for the GCP LB Request Count monitor | `string` | `"sum"` | no | +| [request\_count\_timeframe](#input\_request\_count\_timeframe) | Timeframe for the GCP LB Request Count monitor | `string` | `"last_5m"` | no | +| [request\_count\_timeshift](#input\_request\_count\_timeshift) | Timeshift for the GCP LB Request Count monitor | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [backend\_latency\_bucket\_id](#output\_backend\_latency\_bucket\_id) | id for monitor backend\_latency\_bucket | +| [backend\_latency\_service\_id](#output\_backend\_latency\_service\_id) | id for monitor backend\_latency\_service | +| [error\_rate\_4xx\_id](#output\_error\_rate\_4xx\_id) | id for monitor error\_rate\_4xx | +| [error\_rate\_5xx\_id](#output\_error\_rate\_5xx\_id) | id for monitor error\_rate\_5xx | +| [request\_count\_id](#output\_request\_count\_id) | id for monitor request\_count | +## Related documentation + +* [GCP LB Metrics](https://cloud.google.com/monitoring/api/metrics_gcp#gcp-loadbalancing) +* [Datadog GCP integration](https://docs.datadoghq.com/integrations/google_cloud_platform/) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/lb/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/lb/inputs.tf new file mode 100755 index 0000000..1009608 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/lb/inputs.tf @@ -0,0 +1,280 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags" { + description = "Tags used for filtering" + default = "*" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds for the new host evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# +# 4XX Errors +# +variable "error_rate_4xx_message" { + description = "Custom message for the GCP LB 4XX Errors monitor" + type = string + default = "" +} + +variable "error_rate_4xx_time_aggregator" { + description = "Timeframe for the GCP LB 4XX Errors monitor" + type = string + default = "min" +} + +variable "error_rate_4xx_timeframe" { + description = "Timeframe for the GCP LB 4XX Errors monitor" + type = string + default = "last_5m" +} + +variable "error_rate_4xx_artificial_request" { + description = "Divisor Delta for the GCP LB 4XX Errors monitor" + type = string + default = 5 +} + +variable "error_rate_4xx_threshold_warning" { + description = "Rate error in percentage (warning threshold)" + type = string + default = 50 +} + +variable "error_rate_4xx_threshold_critical" { + description = "Rate error in percentage (critical threshold)" + type = string + default = 60 +} + +variable "error_rate_4xx_enabled" { + description = "Flag to enable GCP LB 4XX Errors monitor" + type = string + default = "true" +} + +variable "error_rate_4xx_extra_tags" { + description = "Extra tags for GCP LB 4XX Errors monitor" + type = list(string) + default = [] +} + +# +# 5XX Errors +# +variable "error_rate_5xx_message" { + description = "Custom message for the GCP LB 5XX Errors monitor" + type = string + default = "" +} + +variable "error_rate_5xx_time_aggregator" { + description = "Timeframe for the GCP LB 5XX Errors monitor" + type = string + default = "min" +} + +variable "error_rate_5xx_timeframe" { + description = "Timeframe for the GCP LB 5XX Errors monitor" + type = string + default = "last_5m" +} + +variable "error_rate_5xx_artificial_request" { + description = "Divisor Delta for the GCP LB 5XX Errors monitor" + type = string + default = 5 +} + +variable "error_rate_5xx_threshold_warning" { + description = "Rate error in percentage (warning threshold)" + type = string + default = 30 +} + +variable "error_rate_5xx_threshold_critical" { + description = "Rate error in percentage (critical threshold)" + type = string + default = 40 +} + +variable "error_rate_5xx_enabled" { + description = "Flag to enable GCP LB 5XX Errors monitor" + type = string + default = "true" +} + +variable "error_rate_5xx_extra_tags" { + description = "Extra tags for GCP LB 5XX Errors monitor" + type = list(string) + default = [] +} + +# +# Latency Backend service +# +variable "backend_latency_service_message" { + description = "Custom message for the GCP LB Backend Latency monitor" + type = string + default = "" +} + +variable "backend_latency_service_time_aggregator" { + description = "Timeframe for the GCP LB Backend Latency monitor" + type = string + default = "min" +} + +variable "backend_latency_service_timeframe" { + description = "Timeframe for the GCP LB Backend Latency monitor" + type = string + default = "last_10m" +} + +variable "backend_latency_service_threshold_warning" { + description = "Latency in milliseconds (warning threshold)" + type = string + default = 1000 +} + +variable "backend_latency_service_threshold_critical" { + description = "Latency in milliseconds (critical threshold)" + type = string + default = 1500 +} + +variable "backend_latency_service_enabled" { + description = "Flag to enable GCP LB Backend Latency monitor" + type = string + default = "true" +} + +variable "backend_latency_service_extra_tags" { + description = "Extra tags for GCP LB Backend Latency monitor" + type = list(string) + default = [] +} + +# +# Latency Backend bucket +# +variable "backend_latency_bucket_message" { + description = "Custom message for the GCP LB Backend Latency monitor" + type = string + default = "" +} + +variable "backend_latency_bucket_time_aggregator" { + description = "Timeframe for the GCP LB Backend Latency monitor" + type = string + default = "min" +} + +variable "backend_latency_bucket_timeframe" { + description = "Timeframe for the GCP LB Backend Latency monitor" + type = string + default = "last_10m" +} + +variable "backend_latency_bucket_threshold_warning" { + description = "Latency in milliseconds (warning threshold)" + type = string + default = 4000 +} + +variable "backend_latency_bucket_threshold_critical" { + description = "Latency in milliseconds (critical threshold)" + type = string + default = 8000 +} + +variable "backend_latency_bucket_enabled" { + description = "Flag to enable GCP LB Backend Latency monitor" + type = string + default = "true" +} + +variable "backend_latency_bucket_extra_tags" { + description = "Extra tags for GCP LB Backend Latency monitor" + type = list(string) + default = [] +} + +# +# Request Count +# +variable "request_count_message" { + description = "Custom message for the GCP LB Request Count monitor" + type = string + default = "" +} + +variable "request_count_time_aggregator" { + description = "Timeframe for the GCP LB Request Count monitor" + type = string + default = "sum" +} + +variable "request_count_timeframe" { + description = "Timeframe for the GCP LB Request Count monitor" + type = string + default = "last_5m" +} + +variable "request_count_timeshift" { + description = "Timeshift for the GCP LB Request Count monitor" + type = string + default = "last_5m" +} + +variable "request_count_threshold_warning" { + description = "Desviation in percentage (warning threshold)" + type = string + default = 250 +} + +variable "request_count_threshold_critical" { + description = "Desviation in percentage (critical threshold)" + type = string + default = 500 +} + +variable "request_count_enabled" { + description = "Flag to enable GCP LB Request Count monitor" + type = string + default = "true" +} + +variable "request_count_extra_tags" { + description = "Extra tags for GCP LB Request Count monitor" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/lb/monitors-lb.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/lb/monitors-lb.tf new file mode 100755 index 0000000..6dae71d --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/lb/monitors-lb.tf @@ -0,0 +1,167 @@ +# +# 4XX Errors +# +resource "datadog_monitor" "error_rate_4xx" { + count = var.error_rate_4xx_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP LB 4xx errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.error_rate_4xx_message, var.message) + type = "query alert" + + query = < ${var.error_rate_4xx_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.error_rate_4xx_threshold_warning + critical = var.error_rate_4xx_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:lb", "team:claranet", "created-by:terraform"], var.error_rate_4xx_extra_tags) +} + +# +# 5XX Errors +# +resource "datadog_monitor" "error_rate_5xx" { + count = var.error_rate_5xx_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP LB 5xx errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.error_rate_5xx_message, var.message) + type = "query alert" + + query = < ${var.error_rate_5xx_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.error_rate_5xx_threshold_warning + critical = var.error_rate_5xx_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:lb", "team:claranet", "created-by:terraform"], var.error_rate_5xx_extra_tags) +} + +# +# Backend Latency for service +# +resource "datadog_monitor" "backend_latency_service" { + count = var.backend_latency_service_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP LB service backend latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.backend_latency_service_message, var.message) + type = "query alert" + + query = < ${var.backend_latency_service_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.backend_latency_service_threshold_warning + critical = var.backend_latency_service_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:lb", "team:claranet", "created-by:terraform"], var.backend_latency_service_extra_tags) +} + +# +# Backend Latency for bucket +# +resource "datadog_monitor" "backend_latency_bucket" { + count = var.backend_latency_bucket_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP LB bucket backend latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.backend_latency_bucket_message, var.message) + type = "query alert" + + query = < ${var.backend_latency_bucket_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.backend_latency_bucket_threshold_warning + critical = var.backend_latency_bucket_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:lb", "team:claranet", "created-by:terraform"], var.backend_latency_bucket_extra_tags) +} + +# +# Request Count +# +resource "datadog_monitor" "request_count" { + count = var.request_count_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP LB Requests count increased abruptly {{#is_alert}}{{value}}%%{{/is_alert}}{{#is_warning}}{{value}}%%{{/is_warning}}" + message = coalesce(var.request_count_message, var.message) + type = "query alert" + + query = < ${var.request_count_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.request_count_threshold_warning + critical = var.request_count_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:lb", "team:claranet", "created-by:terraform"], var.request_count_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/lb/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/lb/outputs.tf new file mode 100755 index 0000000..27a0d60 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/lb/outputs.tf @@ -0,0 +1,25 @@ +output "backend_latency_bucket_id" { + description = "id for monitor backend_latency_bucket" + value = datadog_monitor.backend_latency_bucket.*.id +} + +output "backend_latency_service_id" { + description = "id for monitor backend_latency_service" + value = datadog_monitor.backend_latency_service.*.id +} + +output "error_rate_4xx_id" { + description = "id for monitor error_rate_4xx" + value = datadog_monitor.error_rate_4xx.*.id +} + +output "error_rate_5xx_id" { + description = "id for monitor error_rate_5xx" + value = datadog_monitor.error_rate_5xx.*.id +} + +output "request_count_id" { + description = "id for monitor request_count" + value = datadog_monitor.request_count.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/lb/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/lb/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/lb/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/memorystore/redis/MANIFEST.txt b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/memorystore/redis/MANIFEST.txt new file mode 100755 index 0000000..6de6b50 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/memorystore/redis/MANIFEST.txt @@ -0,0 +1 @@ +cloud-gcp diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/memorystore/redis/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/memorystore/redis/README.md new file mode 100755 index 0000000..737c1a5 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/memorystore/redis/README.md @@ -0,0 +1,75 @@ +# CLOUD GCP MEMORYSTORE REDIS DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-gcp-memorystore-redis" { + source = "claranet/monitors/datadog//cloud/gcp/memorystore/redis" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Memorystore Redis system memory usage ratio + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.system_memory_usage_ratio](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags](#input\_filter\_tags) | Tags used for filtering | `string` | `"*"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the new host evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [system\_memory\_usage\_ratio\_enabled](#input\_system\_memory\_usage\_ratio\_enabled) | Flag to enable GCP Memorystore Redis System memory usage ratio monitor | `string` | `"true"` | no | +| [system\_memory\_usage\_ratio\_extra\_tags](#input\_system\_memory\_usage\_ratio\_extra\_tags) | Extra tags for GCP Memorystore Redis System memory usage ratio monitor | `list(string)` | `[]` | no | +| [system\_memory\_usage\_ratio\_message](#input\_system\_memory\_usage\_ratio\_message) | Custom message for Memorystore Redis System memory usage ratio monitor | `string` | `""` | no | +| [system\_memory\_usage\_ratio\_no\_data\_timeframe](#input\_system\_memory\_usage\_ratio\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `20` | no | +| [system\_memory\_usage\_ratio\_threshold\_critical](#input\_system\_memory\_usage\_ratio\_threshold\_critical) | Memorystore Redis System memory usage ratio critical threshold | `string` | `90` | no | +| [system\_memory\_usage\_ratio\_threshold\_warning](#input\_system\_memory\_usage\_ratio\_threshold\_warning) | Memorystore Redis System memory usage ratio warning threshold | `string` | `80` | no | +| [system\_memory\_usage\_ratio\_time\_aggregator](#input\_system\_memory\_usage\_ratio\_time\_aggregator) | Time aggregator for Memorystore Redis System memory usage ratio monitor | `string` | `"min"` | no | +| [system\_memory\_usage\_ratio\_timeframe](#input\_system\_memory\_usage\_ratio\_timeframe) | Timeframe for Memorystore Redis System memory usage ratio monitor | `string` | `"last_10m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [system\_memory\_usage\_ratio\_id](#output\_system\_memory\_usage\_ratio\_id) | id for monitor system\_memory\_usage\_ratio | +## Related documentation + +* [GCP Metrics for Memorystore Redis](https://cloud.google.com/monitoring/api/metrics_gcp#gcp-redis) +* [Datadog integration for GCP Memorystore Redis](https://docs.datadoghq.com/integrations/google_cloud_redis/) +* [Memory management best practices](https://cloud.google.com/memorystore/docs/redis/memory-management-best-practices#monitor_your_instances_memory_usage) +* [Monitoring System memory usage ratio](https://cloud.google.com/memorystore/docs/redis/memory-management-best-practices#system_memory_usage_ratio_2) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/memorystore/redis/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/memorystore/redis/inputs.tf new file mode 100755 index 0000000..b952d15 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/memorystore/redis/inputs.tf @@ -0,0 +1,89 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags" { + description = "Tags used for filtering" + default = "*" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds for the new host evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "system_memory_usage_ratio_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 20 +} + +# +# System memory usage ratio +# + +variable "system_memory_usage_ratio_message" { + description = "Custom message for Memorystore Redis System memory usage ratio monitor" + type = string + default = "" +} + +variable "system_memory_usage_ratio_time_aggregator" { + description = "Time aggregator for Memorystore Redis System memory usage ratio monitor" + type = string + default = "min" +} + +variable "system_memory_usage_ratio_timeframe" { + description = "Timeframe for Memorystore Redis System memory usage ratio monitor" + type = string + default = "last_10m" +} + +variable "system_memory_usage_ratio_threshold_warning" { + description = "Memorystore Redis System memory usage ratio warning threshold" + type = string + default = 80 +} + +variable "system_memory_usage_ratio_threshold_critical" { + description = "Memorystore Redis System memory usage ratio critical threshold" + type = string + default = 90 +} + +variable "system_memory_usage_ratio_enabled" { + description = "Flag to enable GCP Memorystore Redis System memory usage ratio monitor" + type = string + default = "true" +} + +variable "system_memory_usage_ratio_extra_tags" { + description = "Extra tags for GCP Memorystore Redis System memory usage ratio monitor" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/memorystore/redis/monitors-memorystore-redis.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/memorystore/redis/monitors-memorystore-redis.tf new file mode 100755 index 0000000..78708a7 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/memorystore/redis/monitors-memorystore-redis.tf @@ -0,0 +1,33 @@ +# +# System memory usage ratio +# +resource "datadog_monitor" "system_memory_usage_ratio" { + count = var.system_memory_usage_ratio_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Memorystore Redis system memory usage ratio {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + message = coalesce(var.system_memory_usage_ratio_message, var.message) + type = "metric alert" + + query = < ${var.system_memory_usage_ratio_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.system_memory_usage_ratio_threshold_critical + warning = var.system_memory_usage_ratio_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = var.notify_no_data + no_data_timeframe = var.system_memory_usage_ratio_no_data_timeframe + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:memorystore", "team:claranet", "created-by:terraform", "engine:redis"], var.system_memory_usage_ratio_extra_tags) +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/memorystore/redis/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/memorystore/redis/outputs.tf new file mode 100755 index 0000000..4ea39c1 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/memorystore/redis/outputs.tf @@ -0,0 +1,5 @@ +output "system_memory_usage_ratio_id" { + description = "id for monitor system_memory_usage_ratio" + value = datadog_monitor.system_memory_usage_ratio.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/memorystore/redis/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/memorystore/redis/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/memorystore/redis/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/subscription/MANIFEST.txt b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/subscription/MANIFEST.txt new file mode 100755 index 0000000..6de6b50 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/subscription/MANIFEST.txt @@ -0,0 +1 @@ +cloud-gcp diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/subscription/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/subscription/README.md new file mode 100755 index 0000000..60990bf --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/subscription/README.md @@ -0,0 +1,98 @@ +# CLOUD GCP PUBSUB SUBSCRIPTION DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-gcp-pubsub-subscription" { + source = "claranet/monitors/datadog//cloud/gcp/pubsub/subscription" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Pub/Sub Subscription latency on push endpoint +- Pub/Sub Subscription latency on push endpoint changed abnormally (disabled by default) +- Pub/Sub Subscription oldest unacknowledged message + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.oldest_unacked_message_age](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.subscription_push_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.subscription_push_latency_anomaly](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags](#input\_filter\_tags) | Tags used for filtering | `string` | `"*"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the new host evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [oldest\_unacked\_message\_age\_enabled](#input\_oldest\_unacked\_message\_age\_enabled) | Flag to enable GCP Pub/Sub Subscription Oldest Unacked Message Age monitor | `string` | `"true"` | no | +| [oldest\_unacked\_message\_age\_extra\_tags](#input\_oldest\_unacked\_message\_age\_extra\_tags) | Extra tags for GCP Pub/Sub Subscription Oldest Unacked Message Age monitor | `list(string)` | `[]` | no | +| [oldest\_unacked\_message\_age\_message](#input\_oldest\_unacked\_message\_age\_message) | Custom message for the GCP Pub/Sub Subscription Oldest Unacked Message Age monitor | `string` | `""` | no | +| [oldest\_unacked\_message\_age\_threshold\_critical](#input\_oldest\_unacked\_message\_age\_threshold\_critical) | GCP Pub/Sub Subscription Oldest Unacked Message Age critical threshold | `string` | `120` | no | +| [oldest\_unacked\_message\_age\_threshold\_warning](#input\_oldest\_unacked\_message\_age\_threshold\_warning) | GCP Pub/Sub Subscription Oldest Unacked Message Age warning threshold | `string` | `30` | no | +| [oldest\_unacked\_message\_age\_time\_aggregator](#input\_oldest\_unacked\_message\_age\_time\_aggregator) | Time aggregator for the GCP Pub/Sub Subscription Oldest Unacked Message Age monitor | `string` | `"min"` | no | +| [oldest\_unacked\_message\_age\_timeframe](#input\_oldest\_unacked\_message\_age\_timeframe) | Timeframe for the GCP Pub/Sub Subscription Oldest Unacked Message Age monitor | `string` | `"last_5m"` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [subscription\_push\_latency\_anomaly\_alert\_window](#input\_subscription\_push\_latency\_anomaly\_alert\_window) | Alert window. | `string` | `"last_15m"` | no | +| [subscription\_push\_latency\_anomaly\_count\_default\_zero](#input\_subscription\_push\_latency\_anomaly\_count\_default\_zero) | Count default zero. | `string` | `"true"` | no | +| [subscription\_push\_latency\_anomaly\_detection\_algorithm](#input\_subscription\_push\_latency\_anomaly\_detection\_algorithm) | Anomaly Detection Algorithm used | `string` | `"basic"` | no | +| [subscription\_push\_latency\_anomaly\_direction](#input\_subscription\_push\_latency\_anomaly\_direction) | Direction of the anomaly. It can be both, below or above. | `string` | `"above"` | no | +| [subscription\_push\_latency\_anomaly\_enabled](#input\_subscription\_push\_latency\_anomaly\_enabled) | Flag to enable GCP Pub/Sub Subscription Push Latency Anomaly monitor | `string` | `"false"` | no | +| [subscription\_push\_latency\_anomaly\_extra\_tags](#input\_subscription\_push\_latency\_anomaly\_extra\_tags) | Extra tags for GCP Pub/Sub Subscription Push Latency Anomaly monitor | `list(string)` | `[]` | no | +| [subscription\_push\_latency\_anomaly\_interval](#input\_subscription\_push\_latency\_anomaly\_interval) | Interval. | `string` | `60` | no | +| [subscription\_push\_latency\_anomaly\_message](#input\_subscription\_push\_latency\_anomaly\_message) | Custom message for the GCP Pub/Sub Subscription Push Latency Anomaly monitor | `string` | `""` | no | +| [subscription\_push\_latency\_anomaly\_seasonality](#input\_subscription\_push\_latency\_anomaly\_seasonality) | Seasonality of the algorithm | `string` | `"daily"` | no | +| [subscription\_push\_latency\_anomaly\_threshold\_critical](#input\_subscription\_push\_latency\_anomaly\_threshold\_critical) | GCP Pub/Sub Subscription Push Latency Anomaly critical threshold | `string` | `2` | no | +| [subscription\_push\_latency\_anomaly\_threshold\_warning](#input\_subscription\_push\_latency\_anomaly\_threshold\_warning) | GCP Pub/Sub Subscription Push Latency Anomaly warning threshold | `string` | `1` | no | +| [subscription\_push\_latency\_anomaly\_time\_aggregator](#input\_subscription\_push\_latency\_anomaly\_time\_aggregator) | Time aggregator for the GCP Pub/Sub Subscription Push Latency Anomaly monitor | `string` | `"avg"` | no | +| [subscription\_push\_latency\_anomaly\_timeframe](#input\_subscription\_push\_latency\_anomaly\_timeframe) | Timeframe for the GCP Pub/Sub Subscription Push Latency Anomaly monitor | `string` | `"last_10m"` | no | +| [subscription\_push\_latency\_enabled](#input\_subscription\_push\_latency\_enabled) | Flag to enable GCP Pub/Sub Subscription Push Latency High monitor | `string` | `"true"` | no | +| [subscription\_push\_latency\_extra\_tags](#input\_subscription\_push\_latency\_extra\_tags) | Extra tags for GCP Pub/Sub Subscription Push Latency High monitor | `list(string)` | `[]` | no | +| [subscription\_push\_latency\_message](#input\_subscription\_push\_latency\_message) | Custom message for the GCP Pub/Sub Subscription Push Latency High monitor | `string` | `""` | no | +| [subscription\_push\_latency\_threshold\_critical](#input\_subscription\_push\_latency\_threshold\_critical) | GCP Pub/Sub Subscription Push Latency High critical threshold | `string` | `5000` | no | +| [subscription\_push\_latency\_threshold\_warning](#input\_subscription\_push\_latency\_threshold\_warning) | GCP Pub/Sub Subscription Push Latency High warning threshold | `string` | `1000` | no | +| [subscription\_push\_latency\_time\_aggregator](#input\_subscription\_push\_latency\_time\_aggregator) | Time aggregator for the GCP Pub/Sub Subscription Push Latency High monitor | `string` | `"avg"` | no | +| [subscription\_push\_latency\_timeframe](#input\_subscription\_push\_latency\_timeframe) | Timeframe for the GCP Pub/Sub Subscription Push Latency High monitor | `string` | `"last_10m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [oldest\_unacked\_message\_age\_id](#output\_oldest\_unacked\_message\_age\_id) | id for monitor oldest\_unacked\_message\_age | +| [subscription\_push\_latency\_anomaly\_id](#output\_subscription\_push\_latency\_anomaly\_id) | id for monitor subscription\_push\_latency\_anomaly | +| [subscription\_push\_latency\_id](#output\_subscription\_push\_latency\_id) | id for monitor subscription\_push\_latency | +## Related documentation + +* [GCP Pub/Sub Metrics](https://cloud.google.com/monitoring/api/metrics_gcp#gcp-pubsub) +* [Datadog GCP Pub/Sub integration](https://docs.datadoghq.com/integrations/google_cloud_pubsub/) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/subscription/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/subscription/inputs.tf new file mode 100755 index 0000000..204a39c --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/subscription/inputs.tf @@ -0,0 +1,211 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags" { + description = "Tags used for filtering" + default = "*" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds for the new host evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# +# oldest_unacked_message_age +# + +variable "oldest_unacked_message_age_enabled" { + description = "Flag to enable GCP Pub/Sub Subscription Oldest Unacked Message Age monitor" + type = string + default = "true" +} + +variable "oldest_unacked_message_age_message" { + description = "Custom message for the GCP Pub/Sub Subscription Oldest Unacked Message Age monitor" + type = string + default = "" +} + +variable "oldest_unacked_message_age_time_aggregator" { + description = "Time aggregator for the GCP Pub/Sub Subscription Oldest Unacked Message Age monitor" + type = string + default = "min" +} + +variable "oldest_unacked_message_age_timeframe" { + description = "Timeframe for the GCP Pub/Sub Subscription Oldest Unacked Message Age monitor" + type = string + default = "last_5m" +} + +variable "oldest_unacked_message_age_threshold_warning" { + description = "GCP Pub/Sub Subscription Oldest Unacked Message Age warning threshold" + type = string + default = 30 +} + +variable "oldest_unacked_message_age_threshold_critical" { + description = "GCP Pub/Sub Subscription Oldest Unacked Message Age critical threshold" + type = string + default = 120 +} + +variable "oldest_unacked_message_age_extra_tags" { + description = "Extra tags for GCP Pub/Sub Subscription Oldest Unacked Message Age monitor" + type = list(string) + default = [] +} + +# +# subscription_push_latency +# +variable "subscription_push_latency_enabled" { + description = "Flag to enable GCP Pub/Sub Subscription Push Latency High monitor" + type = string + default = "true" +} + +variable "subscription_push_latency_message" { + description = "Custom message for the GCP Pub/Sub Subscription Push Latency High monitor" + type = string + default = "" +} + +variable "subscription_push_latency_time_aggregator" { + description = "Time aggregator for the GCP Pub/Sub Subscription Push Latency High monitor" + type = string + default = "avg" +} + +variable "subscription_push_latency_timeframe" { + description = "Timeframe for the GCP Pub/Sub Subscription Push Latency High monitor" + type = string + default = "last_10m" +} + +variable "subscription_push_latency_threshold_warning" { + description = "GCP Pub/Sub Subscription Push Latency High warning threshold" + type = string + default = 1000 +} + +variable "subscription_push_latency_threshold_critical" { + description = "GCP Pub/Sub Subscription Push Latency High critical threshold" + type = string + default = 5000 +} + +variable "subscription_push_latency_extra_tags" { + description = "Extra tags for GCP Pub/Sub Subscription Push Latency High monitor" + type = list(string) + default = [] +} + +# +# subscription_push_latency_anomaly +# +variable "subscription_push_latency_anomaly_enabled" { + description = "Flag to enable GCP Pub/Sub Subscription Push Latency Anomaly monitor" + type = string + default = "false" +} + +variable "subscription_push_latency_anomaly_message" { + description = "Custom message for the GCP Pub/Sub Subscription Push Latency Anomaly monitor" + type = string + default = "" +} + +variable "subscription_push_latency_anomaly_time_aggregator" { + description = "Time aggregator for the GCP Pub/Sub Subscription Push Latency Anomaly monitor" + type = string + default = "avg" +} + +variable "subscription_push_latency_anomaly_timeframe" { + description = "Timeframe for the GCP Pub/Sub Subscription Push Latency Anomaly monitor" + type = string + default = "last_10m" +} + +variable "subscription_push_latency_anomaly_detection_algorithm" { + description = "Anomaly Detection Algorithm used" + type = string + default = "basic" +} + +variable "subscription_push_latency_anomaly_direction" { + description = "Direction of the anomaly. It can be both, below or above." + type = string + default = "above" +} + +variable "subscription_push_latency_anomaly_alert_window" { + description = "Alert window." + type = string + default = "last_15m" +} + +variable "subscription_push_latency_anomaly_interval" { + description = "Interval." + type = string + default = 60 +} + +variable "subscription_push_latency_anomaly_count_default_zero" { + description = "Count default zero." + type = string + default = "true" +} + +variable "subscription_push_latency_anomaly_seasonality" { + description = "Seasonality of the algorithm" + type = string + default = "daily" +} + +variable "subscription_push_latency_anomaly_threshold_warning" { + description = "GCP Pub/Sub Subscription Push Latency Anomaly warning threshold" + type = string + default = 1 +} + +variable "subscription_push_latency_anomaly_threshold_critical" { + description = "GCP Pub/Sub Subscription Push Latency Anomaly critical threshold" + type = string + default = 2 +} + +variable "subscription_push_latency_anomaly_extra_tags" { + description = "Extra tags for GCP Pub/Sub Subscription Push Latency Anomaly monitor" + type = list(string) + default = [] +} + + + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/subscription/monitors-subscription.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/subscription/monitors-subscription.tf new file mode 100755 index 0000000..701852c --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/subscription/monitors-subscription.tf @@ -0,0 +1,116 @@ +###################### +# All Subscriptions # +###################### + +# +# oldest_unacked_message_age +# +resource "datadog_monitor" "oldest_unacked_message_age" { + count = var.oldest_unacked_message_age_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Pub/Sub Subscription oldest unacknowledged message {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + message = coalesce(var.oldest_unacked_message_age_message, var.message) + type = "query alert" + + query = <= ${var.oldest_unacked_message_age_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.oldest_unacked_message_age_threshold_warning + critical = var.oldest_unacked_message_age_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:pubsub", "category:subscription", "team:claranet", "created-by:terraform"], var.oldest_unacked_message_age_extra_tags) +} + +###################### +# Push Subscriptions # +###################### + +# +# subscription_push_latency +# +resource "datadog_monitor" "subscription_push_latency" { + count = var.subscription_push_latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Pub/Sub Subscription latency on push endpoint {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + message = coalesce(var.subscription_push_latency_message, var.message) + type = "query alert" + + query = <= ${var.subscription_push_latency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.subscription_push_latency_threshold_warning + critical = var.subscription_push_latency_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:pubsub", "category:subscription", "team:claranet", "created-by:terraform"], var.subscription_push_latency_extra_tags) +} + +# +# subscription_push_latency_anomaly +# +resource "datadog_monitor" "subscription_push_latency_anomaly" { + count = var.subscription_push_latency_anomaly_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Pub/Sub Subscription latency on push endpoint changed abnormally {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.subscription_push_latency_anomaly_message, var.message) + type = "query alert" + + query = <= ${var.subscription_push_latency_anomaly_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.subscription_push_latency_anomaly_threshold_warning + critical = var.subscription_push_latency_anomaly_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:pubsub", "category:subscription", "team:claranet", "created-by:terraform"], var.subscription_push_latency_anomaly_extra_tags) +} \ No newline at end of file diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/subscription/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/subscription/outputs.tf new file mode 100755 index 0000000..13883e2 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/subscription/outputs.tf @@ -0,0 +1,15 @@ +output "oldest_unacked_message_age_id" { + description = "id for monitor oldest_unacked_message_age" + value = datadog_monitor.oldest_unacked_message_age.*.id +} + +output "subscription_push_latency_id" { + description = "id for monitor subscription_push_latency" + value = datadog_monitor.subscription_push_latency.*.id +} + +output "subscription_push_latency_anomaly_id" { + description = "id for monitor subscription_push_latency_anomaly" + value = datadog_monitor.subscription_push_latency_anomaly.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/subscription/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/subscription/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/subscription/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/topic/MANIFEST.txt b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/topic/MANIFEST.txt new file mode 100755 index 0000000..6de6b50 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/topic/MANIFEST.txt @@ -0,0 +1 @@ +cloud-gcp diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/topic/README.md b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/topic/README.md new file mode 100755 index 0000000..639cb0a --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/topic/README.md @@ -0,0 +1,91 @@ +# CLOUD GCP PUBSUB TOPIC DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-gcp-pubsub-topic" { + source = "claranet/monitors/datadog//cloud/gcp/pubsub/topic" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Pub/Sub Topic ratio of sending messages with result unavailable +- Pub/Sub Topic sending messages operations +- Pub/Sub Topic sending messages with result unavailable (disabled by default) + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.sending_operations_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.unavailable_sending_operations_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.unavailable_sending_operations_ratio](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags](#input\_filter\_tags) | Tags used for filtering | `string` | `"*"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the new host evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [sending\_operations\_count\_enabled](#input\_sending\_operations\_count\_enabled) | Flag to enable GCP Pub/Sub Unavailable Sending Operations Count monitor | `string` | `"true"` | no | +| [sending\_operations\_count\_extra\_tags](#input\_sending\_operations\_count\_extra\_tags) | Extra tags for GCP Pub/Sub Sending Operations Count monitor | `list(string)` | `[]` | no | +| [sending\_operations\_count\_message](#input\_sending\_operations\_count\_message) | Custom message for the GCP Pub/Sub Sending Operations Count monitor | `string` | `""` | no | +| [sending\_operations\_count\_threshold\_critical](#input\_sending\_operations\_count\_threshold\_critical) | Critical threshold for the number of sending operations. | `string` | `0` | no | +| [sending\_operations\_count\_time\_aggregator](#input\_sending\_operations\_count\_time\_aggregator) | Timeframe for the GCP Pub/Sub Sending Operations Count monitor | `string` | `"sum"` | no | +| [sending\_operations\_count\_timeframe](#input\_sending\_operations\_count\_timeframe) | Timeframe for the GCP Pub/Sub Sending Operations Count monitor | `string` | `"last_30m"` | no | +| [unavailable\_sending\_operations\_count\_enabled](#input\_unavailable\_sending\_operations\_count\_enabled) | Flag to enable GCP Pub/Sub Unavailable Sending Operations Count monitor | `string` | `"false"` | no | +| [unavailable\_sending\_operations\_count\_extra\_tags](#input\_unavailable\_sending\_operations\_count\_extra\_tags) | Extra tags for GCP Pub/Sub Unavailable Sending Operations Count monitor | `list(string)` | `[]` | no | +| [unavailable\_sending\_operations\_count\_message](#input\_unavailable\_sending\_operations\_count\_message) | Custom message for the GCP Pub/Sub Unavailable Sending Operations Count monitor | `string` | `""` | no | +| [unavailable\_sending\_operations\_count\_threshold\_critical](#input\_unavailable\_sending\_operations\_count\_threshold\_critical) | Critical threshold for the number of unavailable sending operations | `string` | `4` | no | +| [unavailable\_sending\_operations\_count\_threshold\_warning](#input\_unavailable\_sending\_operations\_count\_threshold\_warning) | Warning threshold for the number of unavailable sending operations | `string` | `2` | no | +| [unavailable\_sending\_operations\_count\_time\_aggregator](#input\_unavailable\_sending\_operations\_count\_time\_aggregator) | Timeframe for the GCP Pub/Sub Unavailable Sending Operations Count monitor | `string` | `"sum"` | no | +| [unavailable\_sending\_operations\_count\_timeframe](#input\_unavailable\_sending\_operations\_count\_timeframe) | Timeframe for the GCP Pub/Sub Unavailable Sending Operations Count monitor | `string` | `"last_10m"` | no | +| [unavailable\_sending\_operations\_ratio\_enabled](#input\_unavailable\_sending\_operations\_ratio\_enabled) | Flag to enable GCP Pub/Sub Unavailable Sending Operations Ratio monitor | `string` | `"true"` | no | +| [unavailable\_sending\_operations\_ratio\_extra\_tags](#input\_unavailable\_sending\_operations\_ratio\_extra\_tags) | Extra tags for GCP Pub/Sub Unavailable Sending Operations Ratio monitor | `list(string)` | `[]` | no | +| [unavailable\_sending\_operations\_ratio\_message](#input\_unavailable\_sending\_operations\_ratio\_message) | Custom message for the GCP Pub/Sub Unavailable Sending Operations Ratio monitor | `string` | `""` | no | +| [unavailable\_sending\_operations\_ratio\_threshold\_critical](#input\_unavailable\_sending\_operations\_ratio\_threshold\_critical) | Critical threshold (%) for the ratio of unavailable sending operations | `string` | `20` | no | +| [unavailable\_sending\_operations\_ratio\_threshold\_warning](#input\_unavailable\_sending\_operations\_ratio\_threshold\_warning) | Warning threshold (%) for the ratio of unavailable sending operations | `string` | `10` | no | +| [unavailable\_sending\_operations\_ratio\_time\_aggregator](#input\_unavailable\_sending\_operations\_ratio\_time\_aggregator) | Timeframe for the GCP Pub/Sub Unavailable Sending Operations Ratio monitor | `string` | `"sum"` | no | +| [unavailable\_sending\_operations\_ratio\_timeframe](#input\_unavailable\_sending\_operations\_ratio\_timeframe) | Timeframe for the GCP Pub/Sub Unavailable Sending Operations Ratio monitor | `string` | `"last_10m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [sending\_operations\_count\_id](#output\_sending\_operations\_count\_id) | id for monitor sending\_operations\_count | +| [unavailable\_sending\_operations\_count\_id](#output\_unavailable\_sending\_operations\_count\_id) | id for monitor unavailable\_sending\_operations\_count | +| [unavailable\_sending\_operations\_ratio\_id](#output\_unavailable\_sending\_operations\_ratio\_id) | id for monitor unavailable\_sending\_operations\_ratio | +## Related documentation + +* [GCP Pub/Sub Metrics](https://cloud.google.com/monitoring/api/metrics_gcp#gcp-pubsub) +* [Datadog GCP Pub/Sub integration](https://docs.datadoghq.com/integrations/google_cloud_pubsub/) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/topic/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/topic/inputs.tf new file mode 100755 index 0000000..d1b7e91 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/topic/inputs.tf @@ -0,0 +1,165 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags" { + description = "Tags used for filtering" + default = "*" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds for the new host evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# +# Sending Operations Count +# +variable "sending_operations_count_message" { + description = "Custom message for the GCP Pub/Sub Sending Operations Count monitor" + type = string + default = "" +} + +variable "sending_operations_count_time_aggregator" { + description = "Timeframe for the GCP Pub/Sub Sending Operations Count monitor" + type = string + default = "sum" +} + +variable "sending_operations_count_timeframe" { + description = "Timeframe for the GCP Pub/Sub Sending Operations Count monitor" + type = string + default = "last_30m" +} + +variable "sending_operations_count_threshold_critical" { + description = "Critical threshold for the number of sending operations." + type = string + default = 0 +} + +variable "sending_operations_count_enabled" { + description = "Flag to enable GCP Pub/Sub Unavailable Sending Operations Count monitor" + type = string + default = "true" +} + +variable "sending_operations_count_extra_tags" { + description = "Extra tags for GCP Pub/Sub Sending Operations Count monitor" + type = list(string) + default = [] +} + +# +# Unavailable Sending Operations Count +# +variable "unavailable_sending_operations_count_message" { + description = "Custom message for the GCP Pub/Sub Unavailable Sending Operations Count monitor" + type = string + default = "" +} + +variable "unavailable_sending_operations_count_time_aggregator" { + description = "Timeframe for the GCP Pub/Sub Unavailable Sending Operations Count monitor" + type = string + default = "sum" +} + +variable "unavailable_sending_operations_count_timeframe" { + description = "Timeframe for the GCP Pub/Sub Unavailable Sending Operations Count monitor" + type = string + default = "last_10m" +} + +variable "unavailable_sending_operations_count_threshold_warning" { + description = "Warning threshold for the number of unavailable sending operations" + type = string + default = 2 +} + +variable "unavailable_sending_operations_count_threshold_critical" { + description = "Critical threshold for the number of unavailable sending operations" + type = string + default = 4 +} + +variable "unavailable_sending_operations_count_enabled" { + description = "Flag to enable GCP Pub/Sub Unavailable Sending Operations Count monitor" + type = string + default = "false" +} + +variable "unavailable_sending_operations_count_extra_tags" { + description = "Extra tags for GCP Pub/Sub Unavailable Sending Operations Count monitor" + type = list(string) + default = [] +} + +# +# Unavailable Sending Operations Ratio +# +variable "unavailable_sending_operations_ratio_message" { + description = "Custom message for the GCP Pub/Sub Unavailable Sending Operations Ratio monitor" + type = string + default = "" +} + +variable "unavailable_sending_operations_ratio_time_aggregator" { + description = "Timeframe for the GCP Pub/Sub Unavailable Sending Operations Ratio monitor" + type = string + default = "sum" +} + +variable "unavailable_sending_operations_ratio_timeframe" { + description = "Timeframe for the GCP Pub/Sub Unavailable Sending Operations Ratio monitor" + type = string + default = "last_10m" +} + +variable "unavailable_sending_operations_ratio_threshold_warning" { + description = "Warning threshold (%) for the ratio of unavailable sending operations" + type = string + default = 10 +} + +variable "unavailable_sending_operations_ratio_threshold_critical" { + description = "Critical threshold (%) for the ratio of unavailable sending operations" + type = string + default = 20 +} + +variable "unavailable_sending_operations_ratio_enabled" { + description = "Flag to enable GCP Pub/Sub Unavailable Sending Operations Ratio monitor" + type = string + default = "true" +} + +variable "unavailable_sending_operations_ratio_extra_tags" { + description = "Extra tags for GCP Pub/Sub Unavailable Sending Operations Ratio monitor" + type = list(string) + default = [] +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/topic/monitors-topics.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/topic/monitors-topics.tf new file mode 100755 index 0000000..ad3ad54 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/topic/monitors-topics.tf @@ -0,0 +1,99 @@ +# +# Sending Operations Count +# +resource "datadog_monitor" "sending_operations_count" { + count = var.sending_operations_count_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Pub/Sub Topic sending messages operations {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.sending_operations_count_message, var.message) + type = "query alert" + + query = <= ${var.unavailable_sending_operations_count_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.unavailable_sending_operations_count_threshold_warning + critical = var.unavailable_sending_operations_count_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:pubsub", "category:topic", "team:claranet", "created-by:terraform"], var.unavailable_sending_operations_count_extra_tags) +} + +# +# Unavailable Sending Operations Ratio +# +resource "datadog_monitor" "unavailable_sending_operations_ratio" { + count = var.unavailable_sending_operations_ratio_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Pub/Sub Topic ratio of sending messages with result unavailable {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.unavailable_sending_operations_ratio_message, var.message) + type = "query alert" + + query = <= ${var.unavailable_sending_operations_ratio_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.unavailable_sending_operations_ratio_threshold_warning + critical = var.unavailable_sending_operations_ratio_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:pubsub", "category:topic", "team:claranet", "created-by:terraform"], var.unavailable_sending_operations_ratio_extra_tags) +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/topic/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/topic/outputs.tf new file mode 100755 index 0000000..4452e91 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/topic/outputs.tf @@ -0,0 +1,15 @@ +output "sending_operations_count_id" { + description = "id for monitor sending_operations_count" + value = datadog_monitor.sending_operations_count.*.id +} + +output "unavailable_sending_operations_count_id" { + description = "id for monitor unavailable_sending_operations_count" + value = datadog_monitor.unavailable_sending_operations_count.*.id +} + +output "unavailable_sending_operations_ratio_id" { + description = "id for monitor unavailable_sending_operations_ratio" + value = datadog_monitor.unavailable_sending_operations_ratio.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/topic/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/topic/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/cloud/gcp/pubsub/topic/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/common/alerting-message/README.md b/.terraform/modules/datadog-message-alerting-bh-only/common/alerting-message/README.md new file mode 100755 index 0000000..be89cfb --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/common/alerting-message/README.md @@ -0,0 +1,58 @@ +# ALERTING MESSAGE Datadog Generator + +## How to use this module + +``` +module "datadog-message-alerting" { + source = "git::ssh://git@bitbucket.org/morea/terraform.feature.datadog.git//common/alerting-message?ref={revision}" + + message_alert = "${var.oncall_24x7}" + message_warning = "${var.oncall_business_hours}" + message_nodata = "${var.oncall_nodata}" +} +``` + +## Purpose + +Creates a DataDog monitor alert message with the following inputs : + +* A broadcast channel for critical alerts +* A broadcast channel for nodata alerts +* A broadcast channel for warning alerts +* Prepend text free string +* Append text free string + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|:----:|:-----:|:-----:| +| append_text | Optional free text string to append to alert | string | `` | no | +| message_alert | Define a broadcast channel for critical alerts | string | - | yes | +| message_nodata | Define a broadcast channel for nodata alerts | string | `` | no | +| message_warning | Define a broadcast channel for warning alerts | string | - | no | +| prepend_text | Optional free text string to prepend to alert | string | `` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| alerting-message | The generated message string | + +## Related documentation + +Datadog notifications official documentation: [https://docs.datadoghq.com/monitors/notifications/?tab=is_alertis_warning](https://docs.datadoghq.com/monitors/notifications/?tab=is_alertis_warning) + +## Notes + +This module aims to generate a valid message to split notification into different destinations based on its type (alert, warning, no data). + +If this way matchs your need so you should be able to use its output alone directly for your monitors. +You can even use `append_text` and `prepend_text` variables to add context or documentation to monitors. + +Else you can still use its output with one or multiple destinations to use it in your own messsage (i.e. with `{{#is_match}}` splitting mechanism). + +Here is some tips to understand the behavior of this module and espacially its resulted output: +* Only `message_alert` is mandatory +* If `message_warning` or `message_nodata` are not defined it will use `message_alert` by default +* You can "disable" one notification type by set its variable to empty (i.e. `message_warning = ""`) +* feel free to use this module multiple times with different combinations to suit your needs diff --git a/.terraform/modules/datadog-message-alerting-bh-only/common/alerting-message/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/common/alerting-message/inputs.tf new file mode 100755 index 0000000..60c1305 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/common/alerting-message/inputs.tf @@ -0,0 +1,30 @@ +variable "message_alert" { + description = "Define a broadcast channel for critical alerts" + type = string +} + +variable "message_warning" { + description = "Define a broadcast channel for warning alerts" + type = string + default = null +} + +variable "message_nodata" { + description = "Define a broadcast channel for nodata alerts" + type = string + default = null +} + +variable "prepend_text" { + description = "Optional free text string to prepend to alert" + type = string + default = "" +} + +variable "append_text" { + description = "Optional free text string to append to alert" + type = string + default = "" +} + + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/common/alerting-message/main.tf b/.terraform/modules/datadog-message-alerting-bh-only/common/alerting-message/main.tf new file mode 100755 index 0000000..9efb7b7 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/common/alerting-message/main.tf @@ -0,0 +1,19 @@ +data "template_file" "alerting-message" { + template = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cluster_initializing_shards](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.cluster_relocating_shards](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.cluster_status_not_green](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.cluster_unassigned_shards](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.fetch_change](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.fetch_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.field_data_evictions_change](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.flush_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.http_connections_anomaly](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.indexing_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.jvm_gc_old_collection_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.jvm_gc_young_collection_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.jvm_heap_memory_usage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.jvm_memory_old_usage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.jvm_memory_young_usage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.node_free_space](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.not_responding](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.query_cache_evictions_change](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.request_cache_evictions_change](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.search_query_change](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.search_query_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.task_time_in_queue_change](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cluster\_initializing\_shards\_enabled](#input\_cluster\_initializing\_shards\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [cluster\_initializing\_shards\_extra\_tags](#input\_cluster\_initializing\_shards\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [cluster\_initializing\_shards\_message](#input\_cluster\_initializing\_shards\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [cluster\_initializing\_shards\_threshold\_critical](#input\_cluster\_initializing\_shards\_threshold\_critical) | Cluster Status critical threshold | `string` | `2` | no | +| [cluster\_initializing\_shards\_threshold\_warning](#input\_cluster\_initializing\_shards\_threshold\_warning) | Cluster Status warning threshold | `string` | `1` | no | +| [cluster\_initializing\_shards\_time\_aggregator](#input\_cluster\_initializing\_shards\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [cluster\_initializing\_shards\_timeframe](#input\_cluster\_initializing\_shards\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_5m"` | no | +| [cluster\_relocating\_shards\_enabled](#input\_cluster\_relocating\_shards\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [cluster\_relocating\_shards\_extra\_tags](#input\_cluster\_relocating\_shards\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [cluster\_relocating\_shards\_message](#input\_cluster\_relocating\_shards\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [cluster\_relocating\_shards\_threshold\_critical](#input\_cluster\_relocating\_shards\_threshold\_critical) | Cluster Status critical threshold | `string` | `2` | no | +| [cluster\_relocating\_shards\_threshold\_warning](#input\_cluster\_relocating\_shards\_threshold\_warning) | Cluster Status warning threshold | `string` | `1` | no | +| [cluster\_relocating\_shards\_time\_aggregator](#input\_cluster\_relocating\_shards\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [cluster\_relocating\_shards\_timeframe](#input\_cluster\_relocating\_shards\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_5m"` | no | +| [cluster\_status\_not\_green\_enabled](#input\_cluster\_status\_not\_green\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [cluster\_status\_not\_green\_extra\_tags](#input\_cluster\_status\_not\_green\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [cluster\_status\_not\_green\_message](#input\_cluster\_status\_not\_green\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [cluster\_status\_not\_green\_threshold\_critical](#input\_cluster\_status\_not\_green\_threshold\_critical) | Cluster Status critical threshold | `string` | `0` | no | +| [cluster\_status\_not\_green\_threshold\_warning](#input\_cluster\_status\_not\_green\_threshold\_warning) | Cluster Status warning threshold | `string` | `1` | no | +| [cluster\_status\_not\_green\_time\_aggregator](#input\_cluster\_status\_not\_green\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [cluster\_status\_not\_green\_timeframe](#input\_cluster\_status\_not\_green\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_5m"` | no | +| [cluster\_unassigned\_shards\_enabled](#input\_cluster\_unassigned\_shards\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [cluster\_unassigned\_shards\_extra\_tags](#input\_cluster\_unassigned\_shards\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [cluster\_unassigned\_shards\_message](#input\_cluster\_unassigned\_shards\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [cluster\_unassigned\_shards\_threshold\_critical](#input\_cluster\_unassigned\_shards\_threshold\_critical) | Cluster Status critical threshold | `string` | `2` | no | +| [cluster\_unassigned\_shards\_threshold\_warning](#input\_cluster\_unassigned\_shards\_threshold\_warning) | Cluster Status warning threshold | `string` | `1` | no | +| [cluster\_unassigned\_shards\_time\_aggregator](#input\_cluster\_unassigned\_shards\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [cluster\_unassigned\_shards\_timeframe](#input\_cluster\_unassigned\_shards\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [fetch\_change\_enabled](#input\_fetch\_change\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [fetch\_change\_extra\_tags](#input\_fetch\_change\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [fetch\_change\_message](#input\_fetch\_change\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [fetch\_change\_threshold\_critical](#input\_fetch\_change\_threshold\_critical) | Cluster Status critical threshold | `string` | `100` | no | +| [fetch\_change\_threshold\_warning](#input\_fetch\_change\_threshold\_warning) | Cluster Status warning threshold | `string` | `75` | no | +| [fetch\_change\_time\_aggregator](#input\_fetch\_change\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [fetch\_change\_timeframe](#input\_fetch\_change\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_10m"` | no | +| [fetch\_change\_timeshift](#input\_fetch\_change\_timeshift) | Timeshift for the Cluster Status monitor | `string` | `"last_10m"` | no | +| [fetch\_latency\_enabled](#input\_fetch\_latency\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [fetch\_latency\_extra\_tags](#input\_fetch\_latency\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [fetch\_latency\_message](#input\_fetch\_latency\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [fetch\_latency\_threshold\_critical](#input\_fetch\_latency\_threshold\_critical) | Cluster Status critical threshold | `string` | `20` | no | +| [fetch\_latency\_threshold\_warning](#input\_fetch\_latency\_threshold\_warning) | Cluster Status warning threshold | `string` | `10` | no | +| [fetch\_latency\_time\_aggregator](#input\_fetch\_latency\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"min"` | no | +| [fetch\_latency\_timeframe](#input\_fetch\_latency\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_15m"` | no | +| [field\_data\_evictions\_change\_enabled](#input\_field\_data\_evictions\_change\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [field\_data\_evictions\_change\_extra\_tags](#input\_field\_data\_evictions\_change\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [field\_data\_evictions\_change\_message](#input\_field\_data\_evictions\_change\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [field\_data\_evictions\_change\_threshold\_critical](#input\_field\_data\_evictions\_change\_threshold\_critical) | Cluster Status critical threshold | `string` | `120` | no | +| [field\_data\_evictions\_change\_threshold\_warning](#input\_field\_data\_evictions\_change\_threshold\_warning) | Cluster Status warning threshold | `string` | `60` | no | +| [field\_data\_evictions\_change\_time\_aggregator](#input\_field\_data\_evictions\_change\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [field\_data\_evictions\_change\_timeframe](#input\_field\_data\_evictions\_change\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_15m"` | no | +| [field\_data\_evictions\_change\_timeshift](#input\_field\_data\_evictions\_change\_timeshift) | Timeframe for the Cluster Status monitor | `string` | `"last_15m"` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [flush\_latency\_enabled](#input\_flush\_latency\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [flush\_latency\_extra\_tags](#input\_flush\_latency\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [flush\_latency\_message](#input\_flush\_latency\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [flush\_latency\_threshold\_critical](#input\_flush\_latency\_threshold\_critical) | Cluster Status critical threshold | `string` | `150` | no | +| [flush\_latency\_threshold\_warning](#input\_flush\_latency\_threshold\_warning) | Cluster Status warning threshold | `string` | `100` | no | +| [flush\_latency\_time\_aggregator](#input\_flush\_latency\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [flush\_latency\_timeframe](#input\_flush\_latency\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_15m"` | no | +| [http\_connections\_anomaly\_alert\_window](#input\_http\_connections\_anomaly\_alert\_window) | Alert window. | `string` | `"last_15m"` | no | +| [http\_connections\_anomaly\_count\_default\_zero](#input\_http\_connections\_anomaly\_count\_default\_zero) | Count default zero. | `string` | `"true"` | no | +| [http\_connections\_anomaly\_detection\_algorithm](#input\_http\_connections\_anomaly\_detection\_algorithm) | Anomaly Detection Algorithm used | `string` | `"agile"` | no | +| [http\_connections\_anomaly\_deviations](#input\_http\_connections\_anomaly\_deviations) | Deviations to detect the anomaly | `string` | `2` | no | +| [http\_connections\_anomaly\_direction](#input\_http\_connections\_anomaly\_direction) | Direction of the anomaly. It can be both, below or above. | `string` | `"above"` | no | +| [http\_connections\_anomaly\_enabled](#input\_http\_connections\_anomaly\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [http\_connections\_anomaly\_extra\_tags](#input\_http\_connections\_anomaly\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [http\_connections\_anomaly\_interval](#input\_http\_connections\_anomaly\_interval) | Interval. | `string` | `60` | no | +| [http\_connections\_anomaly\_message](#input\_http\_connections\_anomaly\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [http\_connections\_anomaly\_seasonality](#input\_http\_connections\_anomaly\_seasonality) | Seasonality of the algorithm | `string` | `"hourly"` | no | +| [http\_connections\_anomaly\_threshold\_critical](#input\_http\_connections\_anomaly\_threshold\_critical) | Cluster Status critical threshold | `string` | `1` | no | +| [http\_connections\_anomaly\_threshold\_warning](#input\_http\_connections\_anomaly\_threshold\_warning) | Cluster Status warning threshold | `string` | `0.75` | no | +| [http\_connections\_anomaly\_time\_aggregator](#input\_http\_connections\_anomaly\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [http\_connections\_anomaly\_timeframe](#input\_http\_connections\_anomaly\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_4h"` | no | +| [indexing\_latency\_enabled](#input\_indexing\_latency\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [indexing\_latency\_extra\_tags](#input\_indexing\_latency\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [indexing\_latency\_message](#input\_indexing\_latency\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [indexing\_latency\_threshold\_critical](#input\_indexing\_latency\_threshold\_critical) | Cluster Status critical threshold | `string` | `30` | no | +| [indexing\_latency\_threshold\_warning](#input\_indexing\_latency\_threshold\_warning) | Cluster Status warning threshold | `string` | `15` | no | +| [indexing\_latency\_time\_aggregator](#input\_indexing\_latency\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [indexing\_latency\_timeframe](#input\_indexing\_latency\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_10m"` | no | +| [jvm\_gc\_old\_collection\_latency\_enabled](#input\_jvm\_gc\_old\_collection\_latency\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [jvm\_gc\_old\_collection\_latency\_extra\_tags](#input\_jvm\_gc\_old\_collection\_latency\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [jvm\_gc\_old\_collection\_latency\_message](#input\_jvm\_gc\_old\_collection\_latency\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [jvm\_gc\_old\_collection\_latency\_threshold\_critical](#input\_jvm\_gc\_old\_collection\_latency\_threshold\_critical) | Cluster Status critical threshold | `string` | `300` | no | +| [jvm\_gc\_old\_collection\_latency\_threshold\_warning](#input\_jvm\_gc\_old\_collection\_latency\_threshold\_warning) | Cluster Status warning threshold | `string` | `200` | no | +| [jvm\_gc\_old\_collection\_latency\_time\_aggregator](#input\_jvm\_gc\_old\_collection\_latency\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [jvm\_gc\_old\_collection\_latency\_timeframe](#input\_jvm\_gc\_old\_collection\_latency\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_15m"` | no | +| [jvm\_gc\_young\_collection\_latency\_enabled](#input\_jvm\_gc\_young\_collection\_latency\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [jvm\_gc\_young\_collection\_latency\_extra\_tags](#input\_jvm\_gc\_young\_collection\_latency\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [jvm\_gc\_young\_collection\_latency\_message](#input\_jvm\_gc\_young\_collection\_latency\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [jvm\_gc\_young\_collection\_latency\_threshold\_critical](#input\_jvm\_gc\_young\_collection\_latency\_threshold\_critical) | Cluster Status critical threshold | `string` | `40` | no | +| [jvm\_gc\_young\_collection\_latency\_threshold\_warning](#input\_jvm\_gc\_young\_collection\_latency\_threshold\_warning) | Cluster Status warning threshold | `string` | `20` | no | +| [jvm\_gc\_young\_collection\_latency\_time\_aggregator](#input\_jvm\_gc\_young\_collection\_latency\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [jvm\_gc\_young\_collection\_latency\_timeframe](#input\_jvm\_gc\_young\_collection\_latency\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_15m"` | no | +| [jvm\_heap\_memory\_usage\_enabled](#input\_jvm\_heap\_memory\_usage\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [jvm\_heap\_memory\_usage\_extra\_tags](#input\_jvm\_heap\_memory\_usage\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [jvm\_heap\_memory\_usage\_message](#input\_jvm\_heap\_memory\_usage\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [jvm\_heap\_memory\_usage\_threshold\_critical](#input\_jvm\_heap\_memory\_usage\_threshold\_critical) | Cluster Status critical threshold | `string` | `90` | no | +| [jvm\_heap\_memory\_usage\_threshold\_warning](#input\_jvm\_heap\_memory\_usage\_threshold\_warning) | Cluster Status warning threshold | `string` | `80` | no | +| [jvm\_heap\_memory\_usage\_time\_aggregator](#input\_jvm\_heap\_memory\_usage\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [jvm\_heap\_memory\_usage\_timeframe](#input\_jvm\_heap\_memory\_usage\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_5m"` | no | +| [jvm\_memory\_old\_usage\_enabled](#input\_jvm\_memory\_old\_usage\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [jvm\_memory\_old\_usage\_extra\_tags](#input\_jvm\_memory\_old\_usage\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [jvm\_memory\_old\_usage\_message](#input\_jvm\_memory\_old\_usage\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [jvm\_memory\_old\_usage\_threshold\_critical](#input\_jvm\_memory\_old\_usage\_threshold\_critical) | Cluster Status critical threshold | `string` | `90` | no | +| [jvm\_memory\_old\_usage\_threshold\_warning](#input\_jvm\_memory\_old\_usage\_threshold\_warning) | Cluster Status warning threshold | `string` | `80` | no | +| [jvm\_memory\_old\_usage\_time\_aggregator](#input\_jvm\_memory\_old\_usage\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [jvm\_memory\_old\_usage\_timeframe](#input\_jvm\_memory\_old\_usage\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_10m"` | no | +| [jvm\_memory\_young\_usage\_enabled](#input\_jvm\_memory\_young\_usage\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [jvm\_memory\_young\_usage\_extra\_tags](#input\_jvm\_memory\_young\_usage\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [jvm\_memory\_young\_usage\_message](#input\_jvm\_memory\_young\_usage\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [jvm\_memory\_young\_usage\_threshold\_critical](#input\_jvm\_memory\_young\_usage\_threshold\_critical) | Cluster Status critical threshold | `string` | `90` | no | +| [jvm\_memory\_young\_usage\_threshold\_warning](#input\_jvm\_memory\_young\_usage\_threshold\_warning) | Cluster Status warning threshold | `string` | `80` | no | +| [jvm\_memory\_young\_usage\_time\_aggregator](#input\_jvm\_memory\_young\_usage\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [jvm\_memory\_young\_usage\_timeframe](#input\_jvm\_memory\_young\_usage\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_10m"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before begin to monitor new host | `number` | `300` | no | +| [node\_free\_space\_enabled](#input\_node\_free\_space\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [node\_free\_space\_extra\_tags](#input\_node\_free\_space\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [node\_free\_space\_message](#input\_node\_free\_space\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [node\_free\_space\_threshold\_critical](#input\_node\_free\_space\_threshold\_critical) | Cluster Status critical threshold | `string` | `10` | no | +| [node\_free\_space\_threshold\_warning](#input\_node\_free\_space\_threshold\_warning) | Cluster Status warning threshold | `string` | `20` | no | +| [node\_free\_space\_time\_aggregator](#input\_node\_free\_space\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"sum"` | no | +| [node\_free\_space\_timeframe](#input\_node\_free\_space\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_5m"` | no | +| [not\_responding\_enabled](#input\_not\_responding\_enabled) | Flag to enable Elasticsearch does not respond monitor | `string` | `"true"` | no | +| [not\_responding\_extra\_tags](#input\_not\_responding\_extra\_tags) | Extra tags for Elasticsearch does not respond monitor | `list(string)` | `[]` | no | +| [not\_responding\_message](#input\_not\_responding\_message) | Custom message for Elasticsearch does not respond monitor | `string` | `""` | no | +| [not\_responding\_no\_data\_timeframe](#input\_not\_responding\_no\_data\_timeframe) | Elasticsearch not responding monitor no data timeframe | `string` | `10` | no | +| [not\_responding\_threshold\_warning](#input\_not\_responding\_threshold\_warning) | Elasticsearch not responding limit (warning threshold) | `number` | `3` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [query\_cache\_evictions\_change\_enabled](#input\_query\_cache\_evictions\_change\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [query\_cache\_evictions\_change\_extra\_tags](#input\_query\_cache\_evictions\_change\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [query\_cache\_evictions\_change\_message](#input\_query\_cache\_evictions\_change\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [query\_cache\_evictions\_change\_threshold\_critical](#input\_query\_cache\_evictions\_change\_threshold\_critical) | Cluster Status critical threshold | `string` | `120` | no | +| [query\_cache\_evictions\_change\_threshold\_warning](#input\_query\_cache\_evictions\_change\_threshold\_warning) | Cluster Status warning threshold | `string` | `60` | no | +| [query\_cache\_evictions\_change\_time\_aggregator](#input\_query\_cache\_evictions\_change\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [query\_cache\_evictions\_change\_timeframe](#input\_query\_cache\_evictions\_change\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_15m"` | no | +| [query\_cache\_evictions\_change\_timeshift](#input\_query\_cache\_evictions\_change\_timeshift) | Timeframe for the Cluster Status monitor | `string` | `"last_15m"` | no | +| [request\_cache\_evictions\_change\_enabled](#input\_request\_cache\_evictions\_change\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [request\_cache\_evictions\_change\_extra\_tags](#input\_request\_cache\_evictions\_change\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [request\_cache\_evictions\_change\_message](#input\_request\_cache\_evictions\_change\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [request\_cache\_evictions\_change\_threshold\_critical](#input\_request\_cache\_evictions\_change\_threshold\_critical) | Cluster Status critical threshold | `string` | `120` | no | +| [request\_cache\_evictions\_change\_threshold\_warning](#input\_request\_cache\_evictions\_change\_threshold\_warning) | Cluster Status warning threshold | `string` | `60` | no | +| [request\_cache\_evictions\_change\_time\_aggregator](#input\_request\_cache\_evictions\_change\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [request\_cache\_evictions\_change\_timeframe](#input\_request\_cache\_evictions\_change\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_15m"` | no | +| [request\_cache\_evictions\_change\_timeshift](#input\_request\_cache\_evictions\_change\_timeshift) | Timeshift for the Cluster Status monitor | `string` | `"last_15m"` | no | +| [search\_query\_change\_enabled](#input\_search\_query\_change\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [search\_query\_change\_extra\_tags](#input\_search\_query\_change\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [search\_query\_change\_message](#input\_search\_query\_change\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [search\_query\_change\_threshold\_critical](#input\_search\_query\_change\_threshold\_critical) | Cluster Status critical threshold | `string` | `100` | no | +| [search\_query\_change\_threshold\_warning](#input\_search\_query\_change\_threshold\_warning) | Cluster Status warning threshold | `string` | `75` | no | +| [search\_query\_change\_time\_aggregator](#input\_search\_query\_change\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [search\_query\_change\_timeframe](#input\_search\_query\_change\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_10m"` | no | +| [search\_query\_change\_timeshift](#input\_search\_query\_change\_timeshift) | Timeshift for the Cluster Status monitor | `string` | `"last_10m"` | no | +| [search\_query\_latency\_enabled](#input\_search\_query\_latency\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [search\_query\_latency\_extra\_tags](#input\_search\_query\_latency\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [search\_query\_latency\_message](#input\_search\_query\_latency\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [search\_query\_latency\_threshold\_critical](#input\_search\_query\_latency\_threshold\_critical) | Cluster Status critical threshold | `string` | `20` | no | +| [search\_query\_latency\_threshold\_warning](#input\_search\_query\_latency\_threshold\_warning) | Cluster Status warning threshold | `string` | `10` | no | +| [search\_query\_latency\_time\_aggregator](#input\_search\_query\_latency\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [search\_query\_latency\_timeframe](#input\_search\_query\_latency\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_15m"` | no | +| [task\_time\_in\_queue\_change\_enabled](#input\_task\_time\_in\_queue\_change\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [task\_time\_in\_queue\_change\_extra\_tags](#input\_task\_time\_in\_queue\_change\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [task\_time\_in\_queue\_change\_message](#input\_task\_time\_in\_queue\_change\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [task\_time\_in\_queue\_change\_threshold\_critical](#input\_task\_time\_in\_queue\_change\_threshold\_critical) | Cluster Status critical threshold | `string` | `200` | no | +| [task\_time\_in\_queue\_change\_threshold\_warning](#input\_task\_time\_in\_queue\_change\_threshold\_warning) | Cluster Status warning threshold | `string` | `100` | no | +| [task\_time\_in\_queue\_change\_time\_aggregator](#input\_task\_time\_in\_queue\_change\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [task\_time\_in\_queue\_change\_timeframe](#input\_task\_time\_in\_queue\_change\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_10m"` | no | +| [task\_time\_in\_queue\_change\_timeshift](#input\_task\_time\_in\_queue\_change\_timeshift) | Timeshift for the Cluster Status monitor | `string` | `"last_10m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cluster\_initializing\_shards\_id](#output\_cluster\_initializing\_shards\_id) | id for monitor cluster\_initializing\_shards | +| [cluster\_relocating\_shards\_id](#output\_cluster\_relocating\_shards\_id) | id for monitor cluster\_relocating\_shards | +| [cluster\_status\_not\_green\_id](#output\_cluster\_status\_not\_green\_id) | id for monitor cluster\_status\_not\_green | +| [cluster\_unassigned\_shards\_id](#output\_cluster\_unassigned\_shards\_id) | id for monitor cluster\_unassigned\_shards | +| [fetch\_change\_id](#output\_fetch\_change\_id) | id for monitor fetch\_change | +| [fetch\_latency\_id](#output\_fetch\_latency\_id) | id for monitor fetch\_latency | +| [field\_data\_evictions\_change\_id](#output\_field\_data\_evictions\_change\_id) | id for monitor field\_data\_evictions\_change | +| [flush\_latency\_id](#output\_flush\_latency\_id) | id for monitor flush\_latency | +| [http\_connections\_anomaly\_id](#output\_http\_connections\_anomaly\_id) | id for monitor http\_connections\_anomaly | +| [indexing\_latency\_id](#output\_indexing\_latency\_id) | id for monitor indexing\_latency | +| [jvm\_gc\_old\_collection\_latency\_id](#output\_jvm\_gc\_old\_collection\_latency\_id) | id for monitor jvm\_gc\_old\_collection\_latency | +| [jvm\_gc\_young\_collection\_latency\_id](#output\_jvm\_gc\_young\_collection\_latency\_id) | id for monitor jvm\_gc\_young\_collection\_latency | +| [jvm\_heap\_memory\_usage\_id](#output\_jvm\_heap\_memory\_usage\_id) | id for monitor jvm\_heap\_memory\_usage | +| [jvm\_memory\_old\_usage\_id](#output\_jvm\_memory\_old\_usage\_id) | id for monitor jvm\_memory\_old\_usage | +| [jvm\_memory\_young\_usage\_id](#output\_jvm\_memory\_young\_usage\_id) | id for monitor jvm\_memory\_young\_usage | +| [node\_free\_space\_id](#output\_node\_free\_space\_id) | id for monitor node\_free\_space | +| [not\_responding\_id](#output\_not\_responding\_id) | id for monitor not\_responding | +| [query\_cache\_evictions\_change\_id](#output\_query\_cache\_evictions\_change\_id) | id for monitor query\_cache\_evictions\_change | +| [request\_cache\_evictions\_change\_id](#output\_request\_cache\_evictions\_change\_id) | id for monitor request\_cache\_evictions\_change | +| [search\_query\_change\_id](#output\_search\_query\_change\_id) | id for monitor search\_query\_change | +| [search\_query\_latency\_id](#output\_search\_query\_latency\_id) | id for monitor search\_query\_latency | +| [task\_time\_in\_queue\_change\_id](#output\_task\_time\_in\_queue\_change\_id) | id for monitor task\_time\_in\_queue\_change | +## Related documentation +* [Integration Datadog & ElasticSearch](https://docs.datadoghq.com/integrations/elastic/) +* [How to monitor ElasticSearch with Datadog](https://www.datadoghq.com/blog/monitor-elasticsearch-datadog/) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/elasticsearch/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/elasticsearch/inputs.tf new file mode 100755 index 0000000..dc19e6f --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/elasticsearch/inputs.tf @@ -0,0 +1,1103 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before begin to monitor new host" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# +# Cluster Status Not Green +# +variable "cluster_status_not_green_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "cluster_status_not_green_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "cluster_status_not_green_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_5m" +} + +variable "cluster_status_not_green_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 1 +} + +variable "cluster_status_not_green_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 0 +} + +variable "cluster_status_not_green_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "cluster_status_not_green_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Cluster Initializing Shards +# +variable "cluster_initializing_shards_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "cluster_initializing_shards_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "cluster_initializing_shards_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_5m" +} + +variable "cluster_initializing_shards_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 1 +} + +variable "cluster_initializing_shards_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 2 +} + +variable "cluster_initializing_shards_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "cluster_initializing_shards_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Cluster Relocating Shards +# +variable "cluster_relocating_shards_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "cluster_relocating_shards_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "cluster_relocating_shards_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_5m" +} + +variable "cluster_relocating_shards_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 1 +} + +variable "cluster_relocating_shards_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 2 +} + +variable "cluster_relocating_shards_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "cluster_relocating_shards_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Cluster Unassigned Shards +# +variable "cluster_unassigned_shards_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "cluster_unassigned_shards_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "cluster_unassigned_shards_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_5m" +} + +variable "cluster_unassigned_shards_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 1 +} + +variable "cluster_unassigned_shards_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 2 +} + +variable "cluster_unassigned_shards_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "cluster_unassigned_shards_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Free Space in nodes +# +variable "node_free_space_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "node_free_space_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "sum" +} + +variable "node_free_space_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_5m" +} + +variable "node_free_space_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 20 +} + +variable "node_free_space_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 10 +} + +variable "node_free_space_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "node_free_space_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# JVM Heap Memory Usage +# +variable "jvm_heap_memory_usage_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "jvm_heap_memory_usage_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "jvm_heap_memory_usage_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_5m" +} + +variable "jvm_heap_memory_usage_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 80 +} + +variable "jvm_heap_memory_usage_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 90 +} + +variable "jvm_heap_memory_usage_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "jvm_heap_memory_usage_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# JVM Memory Young Usage +# +variable "jvm_memory_young_usage_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "jvm_memory_young_usage_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "jvm_memory_young_usage_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_10m" +} + +variable "jvm_memory_young_usage_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 80 +} + +variable "jvm_memory_young_usage_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 90 +} + +variable "jvm_memory_young_usage_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "jvm_memory_young_usage_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# JVM Memory Old Usage +# +variable "jvm_memory_old_usage_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "jvm_memory_old_usage_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "jvm_memory_old_usage_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_10m" +} + +variable "jvm_memory_old_usage_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 80 +} + +variable "jvm_memory_old_usage_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 90 +} + +variable "jvm_memory_old_usage_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "jvm_memory_old_usage_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# JVM Garbace Collector Old Collection Latency +# +variable "jvm_gc_old_collection_latency_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "jvm_gc_old_collection_latency_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "jvm_gc_old_collection_latency_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_15m" +} + +variable "jvm_gc_old_collection_latency_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 200 +} + +variable "jvm_gc_old_collection_latency_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 300 +} + +variable "jvm_gc_old_collection_latency_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "jvm_gc_old_collection_latency_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# JVM Garbace Collector Young Collection Latency +# +variable "jvm_gc_young_collection_latency_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "jvm_gc_young_collection_latency_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "jvm_gc_young_collection_latency_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_15m" +} + +variable "jvm_gc_young_collection_latency_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 20 +} + +variable "jvm_gc_young_collection_latency_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 40 +} + +variable "jvm_gc_young_collection_latency_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "jvm_gc_young_collection_latency_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Indexing Latency +# +variable "indexing_latency_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "indexing_latency_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "indexing_latency_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_10m" +} + +variable "indexing_latency_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 15 +} + +variable "indexing_latency_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 30 +} + +variable "indexing_latency_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "indexing_latency_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Flush Latency +# +variable "flush_latency_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "flush_latency_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "flush_latency_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_15m" +} + +variable "flush_latency_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 100 +} + +variable "flush_latency_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 150 +} + +variable "flush_latency_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "flush_latency_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Open HTTP Connections Anomaly +# +variable "http_connections_anomaly_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "http_connections_anomaly_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "http_connections_anomaly_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_4h" +} + +variable "http_connections_anomaly_detection_algorithm" { + description = "Anomaly Detection Algorithm used" + type = string + default = "agile" +} + +variable "http_connections_anomaly_deviations" { + description = "Deviations to detect the anomaly" + type = string + default = 2 +} + +variable "http_connections_anomaly_direction" { + description = "Direction of the anomaly. It can be both, below or above." + type = string + default = "above" +} + +variable "http_connections_anomaly_alert_window" { + description = "Alert window." + type = string + default = "last_15m" +} + +variable "http_connections_anomaly_interval" { + description = "Interval." + type = string + default = 60 +} + +variable "http_connections_anomaly_count_default_zero" { + description = "Count default zero." + type = string + default = "true" +} + +variable "http_connections_anomaly_seasonality" { + description = "Seasonality of the algorithm" + type = string + default = "hourly" +} + +variable "http_connections_anomaly_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 0.75 +} + +variable "http_connections_anomaly_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 1 +} + +variable "http_connections_anomaly_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "http_connections_anomaly_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Query Latency +# +variable "search_query_latency_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "search_query_latency_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "search_query_latency_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_15m" +} + +variable "search_query_latency_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 10 +} + +variable "search_query_latency_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 20 +} + +variable "search_query_latency_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "search_query_latency_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Fetch Latency +# +variable "fetch_latency_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "fetch_latency_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "min" +} + +variable "fetch_latency_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_15m" +} + +variable "fetch_latency_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 10 +} + +variable "fetch_latency_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 20 +} + +variable "fetch_latency_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "fetch_latency_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Search Query Change +# +variable "search_query_change_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "search_query_change_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "search_query_change_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_10m" +} + +variable "search_query_change_timeshift" { + description = "Timeshift for the Cluster Status monitor" + type = string + default = "last_10m" +} + +variable "search_query_change_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 75 +} + +variable "search_query_change_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 100 +} + +variable "search_query_change_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "search_query_change_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Fetch Change +# +variable "fetch_change_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "fetch_change_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "fetch_change_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_10m" +} + +variable "fetch_change_timeshift" { + description = "Timeshift for the Cluster Status monitor" + type = string + default = "last_10m" +} + +variable "fetch_change_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 75 +} + +variable "fetch_change_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 100 +} + +variable "fetch_change_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "fetch_change_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Field Data Evictions +# +variable "field_data_evictions_change_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "field_data_evictions_change_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "field_data_evictions_change_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_15m" +} + +variable "field_data_evictions_change_timeshift" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_15m" +} + +variable "field_data_evictions_change_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 60 +} + +variable "field_data_evictions_change_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 120 +} + +variable "field_data_evictions_change_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "field_data_evictions_change_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Query Cache Evictions +# +variable "query_cache_evictions_change_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "query_cache_evictions_change_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "query_cache_evictions_change_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_15m" +} + +variable "query_cache_evictions_change_timeshift" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_15m" +} + +variable "query_cache_evictions_change_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 60 +} + +variable "query_cache_evictions_change_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 120 +} + +variable "query_cache_evictions_change_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "query_cache_evictions_change_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Request Cache Evictions +# +variable "request_cache_evictions_change_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "request_cache_evictions_change_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "request_cache_evictions_change_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_15m" +} + +variable "request_cache_evictions_change_timeshift" { + description = "Timeshift for the Cluster Status monitor" + type = string + default = "last_15m" +} + +variable "request_cache_evictions_change_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 60 +} + +variable "request_cache_evictions_change_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 120 +} + +variable "request_cache_evictions_change_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "request_cache_evictions_change_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Task Time in Queue +# +variable "task_time_in_queue_change_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "task_time_in_queue_change_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "task_time_in_queue_change_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_10m" +} + +variable "task_time_in_queue_change_timeshift" { + description = "Timeshift for the Cluster Status monitor" + type = string + default = "last_10m" +} + +variable "task_time_in_queue_change_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 100 +} + +variable "task_time_in_queue_change_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 200 +} + +variable "task_time_in_queue_change_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "task_time_in_queue_change_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Service Check +# + +variable "not_responding_enabled" { + description = "Flag to enable Elasticsearch does not respond monitor" + type = string + default = "true" +} + +variable "not_responding_message" { + description = "Custom message for Elasticsearch does not respond monitor" + type = string + default = "" +} + +variable "not_responding_threshold_warning" { + description = "Elasticsearch not responding limit (warning threshold)" + default = 3 +} + +variable "not_responding_no_data_timeframe" { + description = "Elasticsearch not responding monitor no data timeframe" + type = string + default = 10 +} + +variable "not_responding_extra_tags" { + description = "Extra tags for Elasticsearch does not respond monitor" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/elasticsearch/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/elasticsearch/modules.tf new file mode 100755 index 0000000..6f3dc60 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/elasticsearch/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "elasticsearch" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/elasticsearch/monitors-elasticsearch.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/elasticsearch/monitors-elasticsearch.tf new file mode 100755 index 0000000..c33ab9a --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/elasticsearch/monitors-elasticsearch.tf @@ -0,0 +1,725 @@ +# +# Service Check +# +resource "datadog_monitor" "not_responding" { + count = var.not_responding_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ElasticSearch does not respond" + message = coalesce(var.not_responding_message, var.message) + type = "service check" + + query = < ${var.cluster_initializing_shards_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.cluster_initializing_shards_threshold_warning + critical = var.cluster_initializing_shards_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.cluster_initializing_shards_extra_tags) +} + +# +# Cluster Relocating Shards +# +resource "datadog_monitor" "cluster_relocating_shards" { + count = var.cluster_relocating_shards_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ElasticSearch Cluster is relocating shards" + message = coalesce(var.cluster_relocating_shards_message, var.message) + type = "metric alert" + + query = < ${var.cluster_relocating_shards_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.cluster_relocating_shards_threshold_warning + critical = var.cluster_relocating_shards_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.cluster_relocating_shards_extra_tags) +} + +# +# Cluster Unassigned Shards +# +resource "datadog_monitor" "cluster_unassigned_shards" { + count = var.cluster_unassigned_shards_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ElasticSearch Cluster has unassigned shards" + message = coalesce(var.cluster_unassigned_shards_message, var.message) + type = "metric alert" + + query = < ${var.cluster_unassigned_shards_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.cluster_unassigned_shards_threshold_warning + critical = var.cluster_unassigned_shards_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.cluster_unassigned_shards_extra_tags) +} + +# +# Free Space in nodes +# +resource "datadog_monitor" "node_free_space" { + count = var.node_free_space_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ElasticSearch free space < 10%" + message = coalesce(var.node_free_space_message, var.message) + + type = "query alert" + + query = < ${var.jvm_heap_memory_usage_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.jvm_heap_memory_usage_threshold_warning + critical = var.jvm_heap_memory_usage_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.jvm_heap_memory_usage_extra_tags) +} + +# +# JVM Memory Young Usage +# +resource "datadog_monitor" "jvm_memory_young_usage" { + count = var.jvm_memory_young_usage_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch JVM memory Young usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.jvm_memory_young_usage_message, var.message) + type = "query alert" + + query = < ${var.jvm_memory_young_usage_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.jvm_memory_young_usage_threshold_warning + critical = var.jvm_memory_young_usage_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.jvm_memory_young_usage_extra_tags) +} + +# +# JVM Memory Old Usage +# +resource "datadog_monitor" "jvm_memory_old_usage" { + count = var.jvm_memory_old_usage_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch JVM memory Old usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.jvm_memory_old_usage_message, var.message) + type = "query alert" + + query = < ${var.jvm_memory_old_usage_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.jvm_memory_old_usage_threshold_warning + critical = var.jvm_memory_old_usage_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.jvm_memory_old_usage_extra_tags) +} + +# +# JVM Garbace Collector Old Collection Latency +# +resource "datadog_monitor" "jvm_gc_old_collection_latency" { + count = var.jvm_gc_old_collection_latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch average Old-generation garbage collections latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.jvm_gc_old_collection_latency_message, var.message) + type = "query alert" + + query = < ${var.jvm_gc_old_collection_latency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.jvm_gc_old_collection_latency_threshold_warning + critical = var.jvm_gc_old_collection_latency_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.jvm_gc_old_collection_latency_extra_tags) +} + +# +# JVM Garbace Collector Young Collection Latency +# +resource "datadog_monitor" "jvm_gc_young_collection_latency" { + count = var.jvm_gc_young_collection_latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch average Young-generation garbage collections latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.jvm_gc_young_collection_latency_message, var.message) + type = "query alert" + + query = < ${var.jvm_gc_young_collection_latency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.jvm_gc_young_collection_latency_threshold_warning + critical = var.jvm_gc_young_collection_latency_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.jvm_gc_young_collection_latency_extra_tags) +} + +# +# Indexing Latency +# +resource "datadog_monitor" "indexing_latency" { + count = var.indexing_latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch average indexing latency by document {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.indexing_latency_message, var.message) + type = "query alert" + + // TODO add tags to filter by node type and do not apply this monitor on non-data nodes + query = < ${var.indexing_latency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.indexing_latency_threshold_warning + critical = var.indexing_latency_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.indexing_latency_extra_tags) +} + +# +# Flush Latency +# +resource "datadog_monitor" "flush_latency" { + count = var.flush_latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch average index flushing to disk latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.flush_latency_message, var.message) + type = "query alert" + + // TODO add tags to filter by node type and do not apply this monitor on non-data nodes + query = < ${var.flush_latency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.flush_latency_threshold_warning + critical = var.flush_latency_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.flush_latency_extra_tags) +} + +# +# Open HTTP Connections Anomaly +# +resource "datadog_monitor" "http_connections_anomaly" { + count = var.http_connections_anomaly_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch number of current open HTTP connections anomaly detected" + message = coalesce(var.http_connections_anomaly_message, var.message) + type = "query alert" + + query = <= ${var.http_connections_anomaly_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.http_connections_anomaly_threshold_warning + critical = var.http_connections_anomaly_threshold_critical + } + + monitor_threshold_windows { + trigger_window = var.http_connections_anomaly_alert_window + recovery_window = var.http_connections_anomaly_alert_window + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.http_connections_anomaly_extra_tags) +} + +# +# Query Latency +# +resource "datadog_monitor" "search_query_latency" { + count = var.search_query_latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch average search query latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.search_query_latency_message, var.message) + type = "query alert" + + // TODO add tags to filter by node type and do not apply this monitor on non-data nodes + query = < ${var.search_query_latency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.search_query_latency_threshold_warning + critical = var.search_query_latency_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.search_query_latency_extra_tags) +} + +# +# Fetch Latency +# +resource "datadog_monitor" "fetch_latency" { + count = var.fetch_latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch average search fetch latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.fetch_latency_message, var.message) + type = "query alert" + + // TODO add tags to filter by node type and do not apply this monitor on non-data nodes + query = < ${var.fetch_latency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.fetch_latency_threshold_warning + critical = var.fetch_latency_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.fetch_latency_extra_tags) +} + +# +# Search Query Change +# +resource "datadog_monitor" "search_query_change" { + count = var.search_query_change_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch change alert on the number of currently active queries" + message = coalesce(var.search_query_change_message, var.message) + type = "query alert" + + query = <= ${var.search_query_change_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.search_query_change_threshold_warning + critical = var.search_query_change_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.search_query_change_extra_tags) +} + +# +# Fetch Change +# +resource "datadog_monitor" "fetch_change" { + count = var.fetch_change_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch change alert on the number of search fetches currently running" + message = coalesce(var.fetch_change_message, var.message) + type = "query alert" + + query = <= ${var.fetch_change_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.fetch_change_threshold_warning + critical = var.fetch_change_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.fetch_change_extra_tags) +} + +# +# Field Data Evictions +# +resource "datadog_monitor" "field_data_evictions_change" { + count = var.field_data_evictions_change_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch change alert on the total number of evictions from the fielddata cache" + message = coalesce(var.field_data_evictions_change_message, var.message) + type = "query alert" + + // TODO add tags to filter by node type and do not apply this monitor on non-data nodes + query = < ${var.field_data_evictions_change_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.field_data_evictions_change_threshold_warning + critical = var.field_data_evictions_change_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.field_data_evictions_change_extra_tags) +} + +# +# Query Cache Evictions +# +resource "datadog_monitor" "query_cache_evictions_change" { + count = var.query_cache_evictions_change_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch change alert on the number of query cache evictions" + message = coalesce(var.query_cache_evictions_change_message, var.message) + type = "query alert" + + // TODO add tags to filter by node type and do not apply this monitor on non-data nodes + query = < ${var.query_cache_evictions_change_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.query_cache_evictions_change_threshold_warning + critical = var.query_cache_evictions_change_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.query_cache_evictions_change_extra_tags) +} + +# +# Request Cache Evictions +# +resource "datadog_monitor" "request_cache_evictions_change" { + count = var.request_cache_evictions_change_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch change alert on the number of request cache evictions" + message = coalesce(var.request_cache_evictions_change_message, var.message) + type = "query alert" + + // TODO add tags to filter by node type and do not apply this monitor on non-data nodes + query = < ${var.request_cache_evictions_change_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.request_cache_evictions_change_threshold_warning + critical = var.request_cache_evictions_change_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.request_cache_evictions_change_extra_tags) +} + +# +# Task Time in Queue +# +resource "datadog_monitor" "task_time_in_queue_change" { + count = var.task_time_in_queue_change_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch change alert on the average time spent by tasks in the queue" + message = coalesce(var.task_time_in_queue_change_message, var.message) + type = "query alert" + + query = < ${var.task_time_in_queue_change_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.task_time_in_queue_change_threshold_warning + critical = var.task_time_in_queue_change_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.task_time_in_queue_change_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/elasticsearch/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/elasticsearch/outputs.tf new file mode 100755 index 0000000..b70b9cb --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/elasticsearch/outputs.tf @@ -0,0 +1,110 @@ +output "cluster_initializing_shards_id" { + description = "id for monitor cluster_initializing_shards" + value = datadog_monitor.cluster_initializing_shards.*.id +} + +output "cluster_relocating_shards_id" { + description = "id for monitor cluster_relocating_shards" + value = datadog_monitor.cluster_relocating_shards.*.id +} + +output "cluster_status_not_green_id" { + description = "id for monitor cluster_status_not_green" + value = datadog_monitor.cluster_status_not_green.*.id +} + +output "cluster_unassigned_shards_id" { + description = "id for monitor cluster_unassigned_shards" + value = datadog_monitor.cluster_unassigned_shards.*.id +} + +output "fetch_change_id" { + description = "id for monitor fetch_change" + value = datadog_monitor.fetch_change.*.id +} + +output "fetch_latency_id" { + description = "id for monitor fetch_latency" + value = datadog_monitor.fetch_latency.*.id +} + +output "field_data_evictions_change_id" { + description = "id for monitor field_data_evictions_change" + value = datadog_monitor.field_data_evictions_change.*.id +} + +output "flush_latency_id" { + description = "id for monitor flush_latency" + value = datadog_monitor.flush_latency.*.id +} + +output "http_connections_anomaly_id" { + description = "id for monitor http_connections_anomaly" + value = datadog_monitor.http_connections_anomaly.*.id +} + +output "indexing_latency_id" { + description = "id for monitor indexing_latency" + value = datadog_monitor.indexing_latency.*.id +} + +output "jvm_gc_old_collection_latency_id" { + description = "id for monitor jvm_gc_old_collection_latency" + value = datadog_monitor.jvm_gc_old_collection_latency.*.id +} + +output "jvm_gc_young_collection_latency_id" { + description = "id for monitor jvm_gc_young_collection_latency" + value = datadog_monitor.jvm_gc_young_collection_latency.*.id +} + +output "jvm_heap_memory_usage_id" { + description = "id for monitor jvm_heap_memory_usage" + value = datadog_monitor.jvm_heap_memory_usage.*.id +} + +output "jvm_memory_old_usage_id" { + description = "id for monitor jvm_memory_old_usage" + value = datadog_monitor.jvm_memory_old_usage.*.id +} + +output "jvm_memory_young_usage_id" { + description = "id for monitor jvm_memory_young_usage" + value = datadog_monitor.jvm_memory_young_usage.*.id +} + +output "node_free_space_id" { + description = "id for monitor node_free_space" + value = datadog_monitor.node_free_space.*.id +} + +output "not_responding_id" { + description = "id for monitor not_responding" + value = datadog_monitor.not_responding.*.id +} + +output "query_cache_evictions_change_id" { + description = "id for monitor query_cache_evictions_change" + value = datadog_monitor.query_cache_evictions_change.*.id +} + +output "request_cache_evictions_change_id" { + description = "id for monitor request_cache_evictions_change" + value = datadog_monitor.request_cache_evictions_change.*.id +} + +output "search_query_change_id" { + description = "id for monitor search_query_change" + value = datadog_monitor.search_query_change.*.id +} + +output "search_query_latency_id" { + description = "id for monitor search_query_latency" + value = datadog_monitor.search_query_latency.*.id +} + +output "task_time_in_queue_change_id" { + description = "id for monitor task_time_in_queue_change" + value = datadog_monitor.task_time_in_queue_change.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/elasticsearch/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/elasticsearch/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/elasticsearch/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/mongodb/README.md b/.terraform/modules/datadog-message-alerting-bh-only/database/mongodb/README.md new file mode 100755 index 0000000..20ea1ee --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/mongodb/README.md @@ -0,0 +1,102 @@ +# DATABASE MONGODB DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-database-mongodb" { + source = "claranet/monitors/datadog//database/mongodb" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- MongoDB primary state +- MongoDB replication lag +- MongoDB secondary missing +- MongoDB too much servers or wrong monitoring config + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | +| [filter-tags-secondary](#module\_filter-tags-secondary) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.mongodb_primary](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mongodb_replication](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mongodb_secondary](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mongodb_server_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [mongodb\_desired\_servers\_count](#input\_mongodb\_desired\_servers\_count) | Number of servers that should be instanciated for this cluster | `number` | `3` | no | +| [mongodb\_lag\_critical](#input\_mongodb\_lag\_critical) | Critical replication lag in s | `number` | `5` | no | +| [mongodb\_lag\_warning](#input\_mongodb\_lag\_warning) | Warn replication lag in s | `number` | `2` | no | +| [mongodb\_primary\_aggregator](#input\_mongodb\_primary\_aggregator) | Monitor aggregator for MongoDB primary state [available values: min, max] | `string` | `"max"` | no | +| [mongodb\_primary\_enabled](#input\_mongodb\_primary\_enabled) | Flag to enable MongoDB primary state monitor | `string` | `"true"` | no | +| [mongodb\_primary\_extra\_tags](#input\_mongodb\_primary\_extra\_tags) | Extra tags for MongoDB primary state monitor | `list(string)` | `[]` | no | +| [mongodb\_primary\_message](#input\_mongodb\_primary\_message) | Custom message for MongoDB primary monitor | `string` | `""` | no | +| [mongodb\_primary\_no\_data\_timeframe](#input\_mongodb\_primary\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [mongodb\_primary\_timeframe](#input\_mongodb\_primary\_timeframe) | Monitor timeframe for MongoDB wrong state for primary node [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1m"` | no | +| [mongodb\_replication\_aggregator](#input\_mongodb\_replication\_aggregator) | Monitor aggregator for MongoDB replication lag [available values: min, max, sum or avg] | `string` | `"avg"` | no | +| [mongodb\_replication\_enabled](#input\_mongodb\_replication\_enabled) | Flag to enable MongoDB replication lag monitor | `string` | `"true"` | no | +| [mongodb\_replication\_extra\_tags](#input\_mongodb\_replication\_extra\_tags) | Extra tags for MongoDB replication lag monitor | `list(string)` | `[]` | no | +| [mongodb\_replication\_message](#input\_mongodb\_replication\_message) | Custom message for MongoDB replication monitor | `string` | `""` | no | +| [mongodb\_replication\_timeframe](#input\_mongodb\_replication\_timeframe) | Monitor timeframe for MongoDB replication lag [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1m"` | no | +| [mongodb\_secondary\_aggregator](#input\_mongodb\_secondary\_aggregator) | Monitor aggregator for MongoDB secondary state [available values: min, max] | `string` | `"max"` | no | +| [mongodb\_secondary\_enabled](#input\_mongodb\_secondary\_enabled) | Flag to enable MongoDB secondary state monitor | `string` | `"true"` | no | +| [mongodb\_secondary\_extra\_tags](#input\_mongodb\_secondary\_extra\_tags) | Extra tags for MongoDB secondary state monitor | `list(string)` | `[]` | no | +| [mongodb\_secondary\_message](#input\_mongodb\_secondary\_message) | Custom message for MongoDB secondary monitor | `string` | `""` | no | +| [mongodb\_secondary\_timeframe](#input\_mongodb\_secondary\_timeframe) | Monitor timeframe for MongoDB wrong state for secondaries nodes [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [mongodb\_server\_count\_aggregator](#input\_mongodb\_server\_count\_aggregator) | Monitor aggregator for MongoDB server count [available values: min, max] | `string` | `"min"` | no | +| [mongodb\_server\_count\_enabled](#input\_mongodb\_server\_count\_enabled) | Flag to enable MongoDB server count monitor | `string` | `"true"` | no | +| [mongodb\_server\_count\_message](#input\_mongodb\_server\_count\_message) | Custom message for MongoDB server count | `string` | `""` | no | +| [mongodb\_server\_count\_timeframe](#input\_mongodb\_server\_count\_timeframe) | Monitor timeframe for MongoDB wrong server count [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [mongodb\_primary\_id](#output\_mongodb\_primary\_id) | id for monitor mongodb\_primary | +| [mongodb\_replication\_id](#output\_mongodb\_replication\_id) | id for monitor mongodb\_replication | +| [mongodb\_secondary\_id](#output\_mongodb\_secondary\_id) | id for monitor mongodb\_secondary | +| [mongodb\_server\_count\_id](#output\_mongodb\_server\_count\_id) | id for monitor mongodb\_server\_count | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/mongo/](https://docs.datadoghq.com/integrations/mongo/) +MongoDB documentation: [https://docs.mongodb.com/manual/administration/monitoring/](https://docs.mongodb.com/manual/administration/monitoring/) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/mongodb/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/mongodb/inputs.tf new file mode 100755 index 0000000..6e62fd0 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/mongodb/inputs.tf @@ -0,0 +1,181 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "mongodb_primary_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "mongodb_desired_servers_count" { + description = "Number of servers that should be instanciated for this cluster" + default = 3 +} + +variable "mongodb_primary_timeframe" { + description = "Monitor timeframe for MongoDB wrong state for primary node [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1m" +} + +variable "mongodb_secondary_timeframe" { + description = "Monitor timeframe for MongoDB wrong state for secondaries nodes [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "mongodb_server_count_timeframe" { + description = "Monitor timeframe for MongoDB wrong server count [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "mongodb_replication_timeframe" { + description = "Monitor timeframe for MongoDB replication lag [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1m" +} + +variable "mongodb_lag_warning" { + description = "Warn replication lag in s" + default = 2 +} + +variable "mongodb_lag_critical" { + description = "Critical replication lag in s" + default = 5 +} + +variable "mongodb_primary_enabled" { + description = "Flag to enable MongoDB primary state monitor" + type = string + default = "true" +} + +variable "mongodb_primary_extra_tags" { + description = "Extra tags for MongoDB primary state monitor" + type = list(string) + default = [] +} + +variable "mongodb_secondary_enabled" { + description = "Flag to enable MongoDB secondary state monitor" + type = string + default = "true" +} + +variable "mongodb_secondary_extra_tags" { + description = "Extra tags for MongoDB secondary state monitor" + type = list(string) + default = [] +} + +variable "mongodb_server_count_enabled" { + description = "Flag to enable MongoDB server count monitor" + type = string + default = "true" +} + +variable "mongodb_replication_enabled" { + description = "Flag to enable MongoDB replication lag monitor" + type = string + default = "true" +} + +variable "mongodb_replication_extra_tags" { + description = "Extra tags for MongoDB replication lag monitor" + type = list(string) + default = [] +} + +variable "mongodb_primary_message" { + description = "Custom message for MongoDB primary monitor" + type = string + default = "" +} + +variable "mongodb_secondary_message" { + description = "Custom message for MongoDB secondary monitor" + type = string + default = "" +} + +variable "mongodb_server_count_message" { + description = "Custom message for MongoDB server count" + type = string + default = "" +} + +variable "mongodb_replication_message" { + description = "Custom message for MongoDB replication monitor" + type = string + default = "" +} + +variable "mongodb_primary_aggregator" { + description = "Monitor aggregator for MongoDB primary state [available values: min, max]" + type = string + default = "max" +} + +variable "mongodb_secondary_aggregator" { + description = "Monitor aggregator for MongoDB secondary state [available values: min, max]" + type = string + default = "max" +} + +variable "mongodb_server_count_aggregator" { + description = "Monitor aggregator for MongoDB server count [available values: min, max]" + type = string + default = "min" +} + +variable "mongodb_replication_aggregator" { + description = "Monitor aggregator for MongoDB replication lag [available values: min, max, sum or avg]" + type = string + default = "avg" +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/mongodb/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/mongodb/modules.tf new file mode 100755 index 0000000..1ff409d --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/mongodb/modules.tf @@ -0,0 +1,21 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "mongodb" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + +module "filter-tags-secondary" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "mongodb" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["replset_state:secondary"] +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/mongodb/monitors-mongo.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/mongodb/monitors-mongo.tf new file mode 100755 index 0000000..6f01088 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/mongodb/monitors-mongo.tf @@ -0,0 +1,111 @@ +resource "datadog_monitor" "mongodb_primary" { + count = var.mongodb_primary_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] MongoDB primary state" + message = coalesce(var.mongodb_primary_message, var.message) + type = "metric alert" + + query = <= 2 +EOQ + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = var.notify_no_data + no_data_timeframe = var.mongodb_primary_no_data_timeframe + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + require_full_window = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mongo", "resource:mongodb", "team:claranet", "created-by:terraform"], var.mongodb_primary_extra_tags) +} + +resource "datadog_monitor" "mongodb_secondary" { + count = var.mongodb_secondary_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] MongoDB secondary missing" + message = coalesce(var.mongodb_secondary_message, var.message) + type = "query alert" + + query = < 1 +EOQ + + monitor_thresholds { + critical = 1 + warning = 0 + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + require_full_window = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mongo", "resource:mongodb", "team:claranet", "created-by:terraform"], var.mongodb_secondary_extra_tags) +} + +resource "datadog_monitor" "mongodb_server_count" { + count = var.mongodb_server_count_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] MongoDB too much servers or wrong monitoring config" + message = coalesce(var.mongodb_server_count_message, var.message) + type = "metric alert" + + query = < 99 +EOQ + + monitor_thresholds { + critical = 99 + warning = var.mongodb_desired_servers_count + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + require_full_window = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mongo", "resource:mongodb", "team:claranet", "created-by:terraform"], var.mongodb_secondary_extra_tags) +} + +resource "datadog_monitor" "mongodb_replication" { + count = var.mongodb_replication_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] MongoDB replication lag" + message = coalesce(var.mongodb_replication_message, var.message) + type = "metric alert" + + query = < ${var.mongodb_lag_critical} +EOQ + + monitor_thresholds { + critical = var.mongodb_lag_critical + warning = var.mongodb_lag_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + require_full_window = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mongo", "resource:mongodb", "team:claranet", "created-by:terraform"], var.mongodb_replication_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/mongodb/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/mongodb/outputs.tf new file mode 100755 index 0000000..64271a4 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/mongodb/outputs.tf @@ -0,0 +1,20 @@ +output "mongodb_primary_id" { + description = "id for monitor mongodb_primary" + value = datadog_monitor.mongodb_primary.*.id +} + +output "mongodb_replication_id" { + description = "id for monitor mongodb_replication" + value = datadog_monitor.mongodb_replication.*.id +} + +output "mongodb_secondary_id" { + description = "id for monitor mongodb_secondary" + value = datadog_monitor.mongodb_secondary.*.id +} + +output "mongodb_server_count_id" { + description = "id for monitor mongodb_server_count" + value = datadog_monitor.mongodb_server_count.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/mongodb/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/mongodb/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/mongodb/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/mysql/README.md b/.terraform/modules/datadog-message-alerting-bh-only/database/mysql/README.md new file mode 100755 index 0000000..be7c9c8 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/mysql/README.md @@ -0,0 +1,178 @@ +# DATABASE MYSQL DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-database-mysql" { + source = "claranet/monitors/datadog//database/mysql" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Mysql Aborted connects +- Mysql Connections limit +- Mysql Innodb buffer pool efficiency +- Mysql Innodb buffer pool utilization +- Mysql queries changed abnormally +- Mysql replication lag (disabled by default) +- Mysql replication status changed abnormally (disabled by default) +- Mysql server does not respond +- Mysql Slow queries +- Mysql threads changed abnormally + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.mysql_aborted](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_availability](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_connection](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_pool_efficiency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_pool_utilization](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_questions_anomaly](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_replication_lag](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_replication_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_slow](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_threads_anomaly](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [mysql\_aborted\_enabled](#input\_mysql\_aborted\_enabled) | Flag to enable MySQL aborted connects monitor | `string` | `"true"` | no | +| [mysql\_aborted\_extra\_tags](#input\_mysql\_aborted\_extra\_tags) | Extra tags for MySQL aborted connects monitor | `list(string)` | `[]` | no | +| [mysql\_aborted\_message](#input\_mysql\_aborted\_message) | Custom message for MySQL aborted connects monitor | `string` | `""` | no | +| [mysql\_aborted\_threshold\_critical](#input\_mysql\_aborted\_threshold\_critical) | Maximum critical acceptable percent of aborted connects | `number` | `10` | no | +| [mysql\_aborted\_threshold\_warning](#input\_mysql\_aborted\_threshold\_warning) | Maximum warning acceptable percent of aborted connects | `number` | `5` | no | +| [mysql\_aborted\_time\_aggregator](#input\_mysql\_aborted\_time\_aggregator) | Monitor time aggregator for MySQL aborted connects monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [mysql\_aborted\_timeframe](#input\_mysql\_aborted\_timeframe) | Monitor timeframe for MySQL aborted connects monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_10m"` | no | +| [mysql\_availability\_enabled](#input\_mysql\_availability\_enabled) | Flag to enable Mysql availability monitor | `string` | `"true"` | no | +| [mysql\_availability\_extra\_tags](#input\_mysql\_availability\_extra\_tags) | Extra tags for Mysql availability monitor | `list(string)` | `[]` | no | +| [mysql\_availability\_message](#input\_mysql\_availability\_message) | Custom message for Mysql availability monitor | `string` | `""` | no | +| [mysql\_availability\_no\_data\_timeframe](#input\_mysql\_availability\_no\_data\_timeframe) | Mysql availability monitor no data timeframe | `string` | `10` | no | +| [mysql\_availability\_threshold\_warning](#input\_mysql\_availability\_threshold\_warning) | Mysql availability monitor (warning threshold) | `string` | `3` | no | +| [mysql\_connection\_enabled](#input\_mysql\_connection\_enabled) | Flag to enable MySQL connection monitor | `string` | `"true"` | no | +| [mysql\_connection\_extra\_tags](#input\_mysql\_connection\_extra\_tags) | Extra tags for MySQL connection monitor | `list(string)` | `[]` | no | +| [mysql\_connection\_message](#input\_mysql\_connection\_message) | Custom message for MySQL connection monitor | `string` | `""` | no | +| [mysql\_connection\_threshold\_critical](#input\_mysql\_connection\_threshold\_critical) | Maximum critical acceptable percent of connections | `number` | `80` | no | +| [mysql\_connection\_threshold\_warning](#input\_mysql\_connection\_threshold\_warning) | Maximum warning acceptable percent of connections | `number` | `70` | no | +| [mysql\_connection\_time\_aggregator](#input\_mysql\_connection\_time\_aggregator) | Monitor time aggregator for MySQL connection monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [mysql\_connection\_timeframe](#input\_mysql\_connection\_timeframe) | Monitor timeframe for MySQL connection monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_10m"` | no | +| [mysql\_pool\_efficiency\_enabled](#input\_mysql\_pool\_efficiency\_enabled) | Flag to enable MySQL innodb buffer pool efficiency monitor | `string` | `"true"` | no | +| [mysql\_pool\_efficiency\_extra\_tags](#input\_mysql\_pool\_efficiency\_extra\_tags) | Extra tags for MySQL innodb buffer pool efficiency monitor | `list(string)` | `[]` | no | +| [mysql\_pool\_efficiency\_message](#input\_mysql\_pool\_efficiency\_message) | Custom message for MySQL innodb buffer pool efficiency monitor | `string` | `""` | no | +| [mysql\_pool\_efficiency\_threshold\_critical](#input\_mysql\_pool\_efficiency\_threshold\_critical) | Maximum critical acceptable percent of innodb buffer pool efficiency | `number` | `30` | no | +| [mysql\_pool\_efficiency\_threshold\_warning](#input\_mysql\_pool\_efficiency\_threshold\_warning) | Maximum warning acceptable percent of innodb buffer pool efficiency | `number` | `20` | no | +| [mysql\_pool\_efficiency\_time\_aggregator](#input\_mysql\_pool\_efficiency\_time\_aggregator) | Monitor time aggregator for MySQL innodb buffer pool efficiency monitor [available values: min, max or avg] | `string` | `"min"` | no | +| [mysql\_pool\_efficiency\_timeframe](#input\_mysql\_pool\_efficiency\_timeframe) | Monitor timeframe for MySQL innodb buffer pool efficiency monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1h"` | no | +| [mysql\_pool\_utilization\_enabled](#input\_mysql\_pool\_utilization\_enabled) | Flag to enable MySQL innodb buffer pool utilization monitor | `string` | `"true"` | no | +| [mysql\_pool\_utilization\_extra\_tags](#input\_mysql\_pool\_utilization\_extra\_tags) | Extra tags for MySQL innodb buffer pool utilization monitor | `list(string)` | `[]` | no | +| [mysql\_pool\_utilization\_message](#input\_mysql\_pool\_utilization\_message) | Custom message for MySQL innodb buffer pool utilization monitor | `string` | `""` | no | +| [mysql\_pool\_utilization\_threshold\_critical](#input\_mysql\_pool\_utilization\_threshold\_critical) | Maximum critical acceptable percent of innodb buffer pool utilization | `number` | `95` | no | +| [mysql\_pool\_utilization\_threshold\_warning](#input\_mysql\_pool\_utilization\_threshold\_warning) | Maximum warning acceptable percent of innodb buffer pool utilization | `number` | `80` | no | +| [mysql\_pool\_utilization\_time\_aggregator](#input\_mysql\_pool\_utilization\_time\_aggregator) | Monitor time aggregator for MySQL innodb buffer pool utilization monitor [available values: min, max or avg] | `string` | `"min"` | no | +| [mysql\_pool\_utilization\_timeframe](#input\_mysql\_pool\_utilization\_timeframe) | Monitor timeframe for MySQL innodb buffer pool utilization monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1h"` | no | +| [mysql\_questions\_alert\_window](#input\_mysql\_questions\_alert\_window) | Alert window. | `string` | `"last_15m"` | no | +| [mysql\_questions\_count\_default\_zero](#input\_mysql\_questions\_count\_default\_zero) | Count default zero. | `string` | `"true"` | no | +| [mysql\_questions\_detection\_algorithm](#input\_mysql\_questions\_detection\_algorithm) | Anomaly Detection Algorithm used | `string` | `"agile"` | no | +| [mysql\_questions\_deviations](#input\_mysql\_questions\_deviations) | Deviations to detect the anomaly | `string` | `5` | no | +| [mysql\_questions\_direction](#input\_mysql\_questions\_direction) | Direction of the anomaly. It can be both, below or above. | `string` | `"both"` | no | +| [mysql\_questions\_enabled](#input\_mysql\_questions\_enabled) | Flag to enable mysql queries monitor | `string` | `"true"` | no | +| [mysql\_questions\_extra\_tags](#input\_mysql\_questions\_extra\_tags) | Extra tags for MySQL queries monitor | `list(string)` | `[]` | no | +| [mysql\_questions\_interval](#input\_mysql\_questions\_interval) | Interval. | `string` | `60` | no | +| [mysql\_questions\_message](#input\_mysql\_questions\_message) | Custom message for MySQL queries monitor | `string` | `""` | no | +| [mysql\_questions\_seasonality](#input\_mysql\_questions\_seasonality) | Seasonality of the algorithm | `string` | `"daily"` | no | +| [mysql\_questions\_threshold\_critical](#input\_mysql\_questions\_threshold\_critical) | Maximum critical acceptable number of queries | `number` | `1` | no | +| [mysql\_questions\_time\_aggregator](#input\_mysql\_questions\_time\_aggregator) | Monitor time aggregator for MySQL queries monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [mysql\_questions\_timeframe](#input\_mysql\_questions\_timeframe) | Monitor timeframe for MySQL queries monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_4h"` | no | +| [mysql\_replication\_lag\_enabled](#input\_mysql\_replication\_lag\_enabled) | Flag to enable mysql replication lag monitor | `string` | `"false"` | no | +| [mysql\_replication\_lag\_extra\_tags](#input\_mysql\_replication\_lag\_extra\_tags) | Extra tags for MySQL replication lag monitor | `list(string)` | `[]` | no | +| [mysql\_replication\_lag\_message](#input\_mysql\_replication\_lag\_message) | Custom message for MySQL replication lag monitor | `string` | `""` | no | +| [mysql\_replication\_lag\_threshold\_critical](#input\_mysql\_replication\_lag\_threshold\_critical) | Maximum critical acceptable seconds of replication lag | `number` | `200` | no | +| [mysql\_replication\_lag\_threshold\_warning](#input\_mysql\_replication\_lag\_threshold\_warning) | Maximum warning acceptable seconds of replication lag | `number` | `100` | no | +| [mysql\_replication\_lag\_time\_aggregator](#input\_mysql\_replication\_lag\_time\_aggregator) | Monitor time aggregator for MySQL replication lag monitor [available values: min, max or avg] | `string` | `"min"` | no | +| [mysql\_replication\_lag\_timeframe](#input\_mysql\_replication\_lag\_timeframe) | Monitor timeframe for MySQL replication lag monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [mysql\_replication\_status\_enabled](#input\_mysql\_replication\_status\_enabled) | Flag to enable mysql replication status monitor | `string` | `"false"` | no | +| [mysql\_replication\_status\_extra\_tags](#input\_mysql\_replication\_status\_extra\_tags) | Extra tags for MySQL replication status monitor | `list(string)` | `[]` | no | +| [mysql\_replication\_status\_message](#input\_mysql\_replication\_status\_message) | Custom message for MySQL replication status monitor | `string` | `""` | no | +| [mysql\_replication\_status\_time\_aggregator](#input\_mysql\_replication\_status\_time\_aggregator) | Monitor time aggregator for MySQL replication status monitor [available values: min, max or avg] | `string` | `"min"` | no | +| [mysql\_replication\_status\_timeframe](#input\_mysql\_replication\_status\_timeframe) | Monitor timeframe for MySQL replication status monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [mysql\_slow\_enabled](#input\_mysql\_slow\_enabled) | Flag to enable MySQL slow queries monitor | `string` | `"true"` | no | +| [mysql\_slow\_extra\_tags](#input\_mysql\_slow\_extra\_tags) | Extra tags for MySQL slow queries monitor | `list(string)` | `[]` | no | +| [mysql\_slow\_message](#input\_mysql\_slow\_message) | Custom message for MySQL slow queries monitor | `string` | `""` | no | +| [mysql\_slow\_threshold\_critical](#input\_mysql\_slow\_threshold\_critical) | Maximum critical acceptable percent of slow queries | `number` | `20` | no | +| [mysql\_slow\_threshold\_warning](#input\_mysql\_slow\_threshold\_warning) | Maximum warning acceptable percent of slow queries | `number` | `5` | no | +| [mysql\_slow\_time\_aggregator](#input\_mysql\_slow\_time\_aggregator) | Monitor time aggregator for MySQL slow queries monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [mysql\_slow\_timeframe](#input\_mysql\_slow\_timeframe) | Monitor timeframe for MySQL slow queries monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [mysql\_threads\_alert\_window](#input\_mysql\_threads\_alert\_window) | Alert window. | `string` | `"last_15m"` | no | +| [mysql\_threads\_count\_default\_zero](#input\_mysql\_threads\_count\_default\_zero) | Count default zero. | `string` | `"true"` | no | +| [mysql\_threads\_detection\_algorithm](#input\_mysql\_threads\_detection\_algorithm) | Anomaly Detection Algorithm used | `string` | `"basic"` | no | +| [mysql\_threads\_deviations](#input\_mysql\_threads\_deviations) | Deviations to detect the anomaly | `string` | `2` | no | +| [mysql\_threads\_direction](#input\_mysql\_threads\_direction) | Direction of the anomaly. It can be both, below or above. | `string` | `"above"` | no | +| [mysql\_threads\_enabled](#input\_mysql\_threads\_enabled) | Flag to enable mysql threads monitor | `string` | `"true"` | no | +| [mysql\_threads\_extra\_tags](#input\_mysql\_threads\_extra\_tags) | Extra tags for MySQL threads monitor | `list(string)` | `[]` | no | +| [mysql\_threads\_interval](#input\_mysql\_threads\_interval) | Interval. | `string` | `60` | no | +| [mysql\_threads\_message](#input\_mysql\_threads\_message) | Custom message for MySQL threads monitor | `string` | `""` | no | +| [mysql\_threads\_seasonality](#input\_mysql\_threads\_seasonality) | Seasonality of the algorithm | `string` | `"daily"` | no | +| [mysql\_threads\_threshold\_critical](#input\_mysql\_threads\_threshold\_critical) | Maximum critical acceptable number of threads | `number` | `1` | no | +| [mysql\_threads\_time\_aggregator](#input\_mysql\_threads\_time\_aggregator) | Monitor time aggregator for MySQL threads monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [mysql\_threads\_timeframe](#input\_mysql\_threads\_timeframe) | Monitor timeframe for MySQL threads monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_4h"` | no | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the metric evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [mysql\_aborted\_id](#output\_mysql\_aborted\_id) | id for monitor mysql\_aborted | +| [mysql\_availability\_id](#output\_mysql\_availability\_id) | id for monitor mysql\_availability | +| [mysql\_connection\_id](#output\_mysql\_connection\_id) | id for monitor mysql\_connection | +| [mysql\_pool\_efficiency\_id](#output\_mysql\_pool\_efficiency\_id) | id for monitor mysql\_pool\_efficiency | +| [mysql\_pool\_utilization\_id](#output\_mysql\_pool\_utilization\_id) | id for monitor mysql\_pool\_utilization | +| [mysql\_questions\_anomaly\_id](#output\_mysql\_questions\_anomaly\_id) | id for monitor mysql\_questions\_anomaly | +| [mysql\_replication\_lag\_id](#output\_mysql\_replication\_lag\_id) | id for monitor mysql\_replication\_lag | +| [mysql\_replication\_status\_id](#output\_mysql\_replication\_status\_id) | id for monitor mysql\_replication\_status | +| [mysql\_slow\_id](#output\_mysql\_slow\_id) | id for monitor mysql\_slow | +| [mysql\_threads\_anomaly\_id](#output\_mysql\_threads\_anomaly\_id) | id for monitor mysql\_threads\_anomaly | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/mysql/](https://docs.datadoghq.com/integrations/mysql/) + +## Notes + +It could be not possible to modify `innodb_buffer_pool_size` or `innodb_buffer_pool_instances` mysql parameters (i.e. cloudsql). +In this case, InnoDB Pool monitors could be less useful for optimization even if they could inform when an instance should be upsized. diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/mysql/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/mysql/inputs.tf new file mode 100755 index 0000000..1de13b3 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/mysql/inputs.tf @@ -0,0 +1,539 @@ +variable "environment" { + description = "Environment" + type = string +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds for the metric evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# MySQL specific + +################################# +### MySQL availability ### +################################# + +variable "mysql_availability_enabled" { + description = "Flag to enable Mysql availability monitor" + type = string + default = "true" +} + +variable "mysql_availability_extra_tags" { + description = "Extra tags for Mysql availability monitor" + type = list(string) + default = [] +} + +variable "mysql_availability_message" { + description = "Custom message for Mysql availability monitor" + type = string + default = "" +} + +variable "mysql_availability_threshold_warning" { + description = "Mysql availability monitor (warning threshold)" + type = string + default = 3 +} + +variable "mysql_availability_no_data_timeframe" { + description = "Mysql availability monitor no data timeframe" + type = string + default = 10 +} + +################################# +### MySQL connections ### +################################# + +variable "mysql_connection_enabled" { + description = "Flag to enable MySQL connection monitor" + type = string + default = "true" +} + +variable "mysql_connection_extra_tags" { + description = "Extra tags for MySQL connection monitor" + type = list(string) + default = [] +} + +variable "mysql_connection_message" { + description = "Custom message for MySQL connection monitor" + type = string + default = "" +} + +variable "mysql_connection_threshold_critical" { + default = 80 + description = "Maximum critical acceptable percent of connections" +} + +variable "mysql_connection_threshold_warning" { + default = 70 + description = "Maximum warning acceptable percent of connections" +} + +variable "mysql_connection_time_aggregator" { + description = "Monitor time aggregator for MySQL connection monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "mysql_connection_timeframe" { + description = "Monitor timeframe for MySQL connection monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_10m" +} + +################################# +### MySQL aborted connects ### +################################# + +variable "mysql_aborted_enabled" { + description = "Flag to enable MySQL aborted connects monitor" + type = string + default = "true" +} + +variable "mysql_aborted_extra_tags" { + description = "Extra tags for MySQL aborted connects monitor" + type = list(string) + default = [] +} + +variable "mysql_aborted_message" { + description = "Custom message for MySQL aborted connects monitor" + type = string + default = "" +} + +variable "mysql_aborted_threshold_critical" { + default = 10 + description = "Maximum critical acceptable percent of aborted connects" +} + +variable "mysql_aborted_threshold_warning" { + default = 5 + description = "Maximum warning acceptable percent of aborted connects" +} + +variable "mysql_aborted_time_aggregator" { + description = "Monitor time aggregator for MySQL aborted connects monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "mysql_aborted_timeframe" { + description = "Monitor timeframe for MySQL aborted connects monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_10m" +} + +################################# +### MySQL slow queries ### +################################# + +variable "mysql_slow_enabled" { + description = "Flag to enable MySQL slow queries monitor" + type = string + default = "true" +} + +variable "mysql_slow_extra_tags" { + description = "Extra tags for MySQL slow queries monitor" + type = list(string) + default = [] +} + +variable "mysql_slow_message" { + description = "Custom message for MySQL slow queries monitor" + type = string + default = "" +} + +variable "mysql_slow_threshold_critical" { + default = 20 + description = "Maximum critical acceptable percent of slow queries" +} + +variable "mysql_slow_threshold_warning" { + default = 5 + description = "Maximum warning acceptable percent of slow queries" +} + +variable "mysql_slow_time_aggregator" { + description = "Monitor time aggregator for MySQL slow queries monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "mysql_slow_timeframe" { + description = "Monitor timeframe for MySQL slow queries monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +################################# +# MySQL innodb pool efficiency # +################################# + +variable "mysql_pool_efficiency_enabled" { + description = "Flag to enable MySQL innodb buffer pool efficiency monitor" + type = string + default = "true" +} + +variable "mysql_pool_efficiency_extra_tags" { + description = "Extra tags for MySQL innodb buffer pool efficiency monitor" + type = list(string) + default = [] +} + +variable "mysql_pool_efficiency_message" { + description = "Custom message for MySQL innodb buffer pool efficiency monitor" + type = string + default = "" +} + +variable "mysql_pool_efficiency_threshold_critical" { + default = 30 + description = "Maximum critical acceptable percent of innodb buffer pool efficiency" +} + +variable "mysql_pool_efficiency_threshold_warning" { + default = 20 + description = "Maximum warning acceptable percent of innodb buffer pool efficiency" +} + +variable "mysql_pool_efficiency_time_aggregator" { + description = "Monitor time aggregator for MySQL innodb buffer pool efficiency monitor [available values: min, max or avg]" + type = string + default = "min" +} + +variable "mysql_pool_efficiency_timeframe" { + description = "Monitor timeframe for MySQL innodb buffer pool efficiency monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1h" +} + +################################# +# MySQL innodb pool utilization # +################################# + +variable "mysql_pool_utilization_enabled" { + description = "Flag to enable MySQL innodb buffer pool utilization monitor" + type = string + default = "true" +} + +variable "mysql_pool_utilization_extra_tags" { + description = "Extra tags for MySQL innodb buffer pool utilization monitor" + type = list(string) + default = [] +} + +variable "mysql_pool_utilization_message" { + description = "Custom message for MySQL innodb buffer pool utilization monitor" + type = string + default = "" +} + +variable "mysql_pool_utilization_threshold_critical" { + default = 95 + description = "Maximum critical acceptable percent of innodb buffer pool utilization" +} + +variable "mysql_pool_utilization_threshold_warning" { + default = 80 + description = "Maximum warning acceptable percent of innodb buffer pool utilization" +} + +variable "mysql_pool_utilization_time_aggregator" { + description = "Monitor time aggregator for MySQL innodb buffer pool utilization monitor [available values: min, max or avg]" + type = string + default = "min" +} + +variable "mysql_pool_utilization_timeframe" { + description = "Monitor timeframe for MySQL innodb buffer pool utilization monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1h" +} + +################################# +### MySQL threads ### +################################# + +variable "mysql_threads_enabled" { + description = "Flag to enable mysql threads monitor" + type = string + default = "true" +} + +variable "mysql_threads_extra_tags" { + description = "Extra tags for MySQL threads monitor" + type = list(string) + default = [] +} + +variable "mysql_threads_message" { + description = "Custom message for MySQL threads monitor" + type = string + default = "" +} + +variable "mysql_threads_threshold_critical" { + default = 1 + description = "Maximum critical acceptable number of threads" +} + +variable "mysql_threads_detection_algorithm" { + description = "Anomaly Detection Algorithm used" + type = string + default = "basic" +} + +variable "mysql_threads_deviations" { + description = "Deviations to detect the anomaly" + type = string + default = 2 +} + +variable "mysql_threads_direction" { + description = "Direction of the anomaly. It can be both, below or above." + type = string + default = "above" +} + +variable "mysql_threads_alert_window" { + description = "Alert window." + type = string + default = "last_15m" +} + +variable "mysql_threads_interval" { + description = "Interval." + type = string + default = 60 +} + +variable "mysql_threads_count_default_zero" { + description = "Count default zero." + type = string + default = "true" +} + +variable "mysql_threads_seasonality" { + description = "Seasonality of the algorithm" + type = string + default = "daily" +} + +variable "mysql_threads_time_aggregator" { + description = "Monitor time aggregator for MySQL threads monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "mysql_threads_timeframe" { + description = "Monitor timeframe for MySQL threads monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_4h" +} + +################################# +### MySQL queries ### +################################# + +variable "mysql_questions_enabled" { + description = "Flag to enable mysql queries monitor" + type = string + default = "true" +} + +variable "mysql_questions_extra_tags" { + description = "Extra tags for MySQL queries monitor" + type = list(string) + default = [] +} + +variable "mysql_questions_message" { + description = "Custom message for MySQL queries monitor" + type = string + default = "" +} + +variable "mysql_questions_threshold_critical" { + default = 1 + description = "Maximum critical acceptable number of queries" +} + +variable "mysql_questions_detection_algorithm" { + description = "Anomaly Detection Algorithm used" + type = string + default = "agile" +} + +variable "mysql_questions_deviations" { + description = "Deviations to detect the anomaly" + type = string + default = 5 +} + +variable "mysql_questions_direction" { + description = "Direction of the anomaly. It can be both, below or above." + type = string + default = "both" +} + +variable "mysql_questions_alert_window" { + description = "Alert window." + type = string + default = "last_15m" +} + +variable "mysql_questions_interval" { + description = "Interval." + type = string + default = 60 +} + +variable "mysql_questions_count_default_zero" { + description = "Count default zero." + type = string + default = "true" +} + +variable "mysql_questions_seasonality" { + description = "Seasonality of the algorithm" + type = string + default = "daily" +} + +variable "mysql_questions_time_aggregator" { + description = "Monitor time aggregator for MySQL queries monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "mysql_questions_timeframe" { + description = "Monitor timeframe for MySQL queries monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_4h" +} + +################################# +### MySQL replication lag ### +################################# + +variable "mysql_replication_lag_enabled" { + description = "Flag to enable mysql replication lag monitor" + type = string + default = "false" +} + +variable "mysql_replication_lag_extra_tags" { + description = "Extra tags for MySQL replication lag monitor" + type = list(string) + default = [] +} + +variable "mysql_replication_lag_message" { + description = "Custom message for MySQL replication lag monitor" + type = string + default = "" +} + +variable "mysql_replication_lag_threshold_warning" { + default = 100 + description = "Maximum warning acceptable seconds of replication lag" +} + +variable "mysql_replication_lag_threshold_critical" { + default = 200 + description = "Maximum critical acceptable seconds of replication lag" +} + +variable "mysql_replication_lag_time_aggregator" { + description = "Monitor time aggregator for MySQL replication lag monitor [available values: min, max or avg]" + type = string + default = "min" +} + +variable "mysql_replication_lag_timeframe" { + description = "Monitor timeframe for MySQL replication lag monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +################################### +### MySQL replication status ### +################################### + +variable "mysql_replication_status_enabled" { + description = "Flag to enable mysql replication status monitor" + type = string + default = "false" +} + +variable "mysql_replication_status_extra_tags" { + description = "Extra tags for MySQL replication status monitor" + type = list(string) + default = [] +} + +variable "mysql_replication_status_message" { + description = "Custom message for MySQL replication status monitor" + type = string + default = "" +} + +variable "mysql_replication_status_time_aggregator" { + description = "Monitor time aggregator for MySQL replication status monitor [available values: min, max or avg]" + type = string + default = "min" +} + +variable "mysql_replication_status_timeframe" { + description = "Monitor timeframe for MySQL replication status monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/mysql/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/mysql/modules.tf new file mode 100755 index 0000000..37d1850 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/mysql/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "mysql" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/mysql/monitors-mysql.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/mysql/monitors-mysql.tf new file mode 100755 index 0000000..5534907 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/mysql/monitors-mysql.tf @@ -0,0 +1,309 @@ +resource "datadog_monitor" "mysql_availability" { + count = var.mysql_availability_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql server does not respond" + message = coalesce(var.mysql_availability_message, var.message) + type = "service check" + + query = < ${var.mysql_connection_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.mysql_connection_threshold_warning + critical = var.mysql_connection_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mysql", "resource:mysql", "team:claranet", "created-by:terraform"], var.mysql_connection_extra_tags) +} + +resource "datadog_monitor" "mysql_aborted" { + count = var.mysql_aborted_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql Aborted connects {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.mysql_aborted_message, var.message) + type = "query alert" + + query = < ${var.mysql_aborted_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.mysql_aborted_threshold_warning + critical = var.mysql_aborted_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mysql", "resource:mysql", "team:claranet", "created-by:terraform"], var.mysql_aborted_extra_tags) +} + +resource "datadog_monitor" "mysql_slow" { + count = var.mysql_slow_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql Slow queries {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.mysql_slow_message, var.message) + type = "query alert" + + query = < ${var.mysql_slow_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.mysql_slow_threshold_warning + critical = var.mysql_slow_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mysql", "resource:mysql", "team:claranet", "created-by:terraform"], var.mysql_slow_extra_tags) +} + +resource "datadog_monitor" "mysql_pool_efficiency" { + count = var.mysql_pool_efficiency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql Innodb buffer pool efficiency {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.mysql_pool_efficiency_message, var.message) + type = "query alert" + + query = < ${var.mysql_pool_efficiency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.mysql_pool_efficiency_threshold_warning + critical = var.mysql_pool_efficiency_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mysql", "resource:mysql", "team:claranet", "created-by:terraform"], var.mysql_pool_efficiency_extra_tags) +} + +resource "datadog_monitor" "mysql_pool_utilization" { + count = var.mysql_pool_utilization_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql Innodb buffer pool utilization {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.mysql_pool_utilization_message, var.message) + type = "query alert" + + query = < ${var.mysql_pool_utilization_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.mysql_pool_utilization_threshold_warning + critical = var.mysql_pool_utilization_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mysql", "resource:mysql", "team:claranet", "created-by:terraform"], var.mysql_pool_utilization_extra_tags) +} + +resource "datadog_monitor" "mysql_threads_anomaly" { + count = var.mysql_threads_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql threads changed abnormally" + message = coalesce(var.mysql_threads_message, var.message) + type = "metric alert" + + query = <= ${var.mysql_threads_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.mysql_threads_threshold_critical + critical_recovery = 0 + } + + monitor_threshold_windows { + trigger_window = var.mysql_threads_alert_window + recovery_window = var.mysql_threads_alert_window + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mysql", "resource:mysql", "team:claranet", "created-by:terraform"], var.mysql_threads_extra_tags) +} + +resource "datadog_monitor" "mysql_questions_anomaly" { + count = var.mysql_questions_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql queries changed abnormally" + message = coalesce(var.mysql_questions_message, var.message) + type = "metric alert" + + query = <= ${var.mysql_questions_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.mysql_questions_threshold_critical + critical_recovery = 0 + } + + monitor_threshold_windows { + trigger_window = var.mysql_questions_alert_window + recovery_window = var.mysql_questions_alert_window + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mysql", "resource:mysql", "team:claranet", "created-by:terraform"], var.mysql_questions_extra_tags) +} + +resource "datadog_monitor" "mysql_replication_lag" { + count = var.mysql_replication_lag_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql replication lag {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + message = coalesce(var.mysql_replication_lag_message, var.message) + type = "query alert" + + query = < ${var.mysql_replication_lag_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.mysql_replication_lag_threshold_warning + critical = var.mysql_replication_lag_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mysql", "resource:mysql", "team:claranet", "created-by:terraform"], var.mysql_replication_lag_extra_tags) +} + +resource "datadog_monitor" "mysql_replication_status" { + count = var.mysql_replication_status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql replication status changed abnormally" + message = coalesce(var.mysql_replication_status_message, var.message) + type = "metric alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.postgresql_availability](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.postgresql_connection_too_high](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.postgresql_too_many_locks](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the metric evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [postgresql\_availability\_enabled](#input\_postgresql\_availability\_enabled) | Flag to enable PostgreSQL availability monitor | `string` | `"true"` | no | +| [postgresql\_availability\_extra\_tags](#input\_postgresql\_availability\_extra\_tags) | Extra tags for PostgreSQL availability monitor | `list(string)` | `[]` | no | +| [postgresql\_availability\_message](#input\_postgresql\_availability\_message) | Custom message for PostgreSQL availability monitor | `string` | `""` | no | +| [postgresql\_availability\_no\_data\_timeframe](#input\_postgresql\_availability\_no\_data\_timeframe) | PostgreSQL availability monitor no data timeframe | `string` | `10` | no | +| [postgresql\_availability\_threshold\_warning](#input\_postgresql\_availability\_threshold\_warning) | PostgreSQL availability monitor (warning threshold) | `string` | `3` | no | +| [postgresql\_connection\_enabled](#input\_postgresql\_connection\_enabled) | Flag to enable PostgreSQL connection monitor | `string` | `"true"` | no | +| [postgresql\_connection\_extra\_tags](#input\_postgresql\_connection\_extra\_tags) | Extra tags for PostgreSQL connection connects monitor | `list(string)` | `[]` | no | +| [postgresql\_connection\_message](#input\_postgresql\_connection\_message) | Custom message for PostgreSQL connection monitor | `string` | `""` | no | +| [postgresql\_connection\_threshold\_critical](#input\_postgresql\_connection\_threshold\_critical) | Maximum critical acceptable percent of connections | `number` | `80` | no | +| [postgresql\_connection\_threshold\_warning](#input\_postgresql\_connection\_threshold\_warning) | Maximum warning acceptable percent of connections | `number` | `70` | no | +| [postgresql\_connection\_time\_aggregator](#input\_postgresql\_connection\_time\_aggregator) | Monitor time aggregator for PostgreSQL connection monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [postgresql\_connection\_timeframe](#input\_postgresql\_connection\_timeframe) | Monitor timeframe for PostgreSQL connection monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [postgresql\_lock\_enabled](#input\_postgresql\_lock\_enabled) | Flag to enable PostgreSQL lock monitor | `string` | `"true"` | no | +| [postgresql\_lock\_extra\_tags](#input\_postgresql\_lock\_extra\_tags) | Extra tags for PostgreSQL lock connects monitor | `list(string)` | `[]` | no | +| [postgresql\_lock\_message](#input\_postgresql\_lock\_message) | Custom message for PostgreSQL lock monitor | `string` | `""` | no | +| [postgresql\_lock\_threshold\_critical](#input\_postgresql\_lock\_threshold\_critical) | Maximum critical acceptable number of locks | `number` | `99` | no | +| [postgresql\_lock\_threshold\_warning](#input\_postgresql\_lock\_threshold\_warning) | Maximum warning acceptable number of locks | `number` | `70` | no | +| [postgresql\_lock\_time\_aggregator](#input\_postgresql\_lock\_time\_aggregator) | Monitor time aggregator for PostgreSQL lock monitor [available values: min, max or avg] | `string` | `"min"` | no | +| [postgresql\_lock\_timeframe](#input\_postgresql\_lock\_timeframe) | Monitor timeframe for PostgreSQL lock monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [postgresql\_availability\_id](#output\_postgresql\_availability\_id) | id for monitor postgresql\_availability | +| [postgresql\_connection\_too\_high\_id](#output\_postgresql\_connection\_too\_high\_id) | id for monitor postgresql\_connection\_too\_high | +| [postgresql\_too\_many\_locks\_id](#output\_postgresql\_too\_many\_locks\_id) | id for monitor postgresql\_too\_many\_locks | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/postgres/](https://docs.datadoghq.com/integrations/postgres/) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/postgresql/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/postgresql/inputs.tf new file mode 100755 index 0000000..1030a74 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/postgresql/inputs.tf @@ -0,0 +1,168 @@ +variable "environment" { + description = "Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds for the metric evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# PostgreSQL specific +################################## +### PostgreSQL availability ### +################################## + +variable "postgresql_availability_enabled" { + description = "Flag to enable PostgreSQL availability monitor" + type = string + default = "true" +} + +variable "postgresql_availability_extra_tags" { + description = "Extra tags for PostgreSQL availability monitor" + type = list(string) + default = [] +} + +variable "postgresql_availability_message" { + description = "Custom message for PostgreSQL availability monitor" + type = string + default = "" +} + +variable "postgresql_availability_threshold_warning" { + description = "PostgreSQL availability monitor (warning threshold)" + type = string + default = 3 +} + +variable "postgresql_availability_no_data_timeframe" { + description = "PostgreSQL availability monitor no data timeframe" + type = string + default = 10 +} + +################################## +### PostgreSQL connections ### +################################## + +variable "postgresql_connection_threshold_critical" { + default = 80 + description = "Maximum critical acceptable percent of connections" +} + +variable "postgresql_connection_threshold_warning" { + default = 70 + description = "Maximum warning acceptable percent of connections" +} + +variable "postgresql_connection_enabled" { + description = "Flag to enable PostgreSQL connection monitor" + type = string + default = "true" +} + +variable "postgresql_connection_extra_tags" { + description = "Extra tags for PostgreSQL connection connects monitor" + type = list(string) + default = [] +} + +variable "postgresql_connection_message" { + description = "Custom message for PostgreSQL connection monitor" + type = string + default = "" +} + +variable "postgresql_connection_time_aggregator" { + description = "Monitor time aggregator for PostgreSQL connection monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "postgresql_connection_timeframe" { + description = "Monitor timeframe for PostgreSQL connection monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +############################ +### PostgreSQL locks ### +############################ + +variable "postgresql_lock_threshold_critical" { + default = 99 + description = "Maximum critical acceptable number of locks" +} + +variable "postgresql_lock_threshold_warning" { + default = 70 + description = "Maximum warning acceptable number of locks" +} + +variable "postgresql_lock_enabled" { + description = "Flag to enable PostgreSQL lock monitor" + type = string + default = "true" +} + +variable "postgresql_lock_extra_tags" { + description = "Extra tags for PostgreSQL lock connects monitor" + type = list(string) + default = [] +} + +variable "postgresql_lock_message" { + description = "Custom message for PostgreSQL lock monitor" + type = string + default = "" +} + +variable "postgresql_lock_time_aggregator" { + description = "Monitor time aggregator for PostgreSQL lock monitor [available values: min, max or avg]" + type = string + default = "min" +} + +variable "postgresql_lock_timeframe" { + description = "Monitor timeframe for PostgreSQL lock monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/postgresql/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/postgresql/modules.tf new file mode 100755 index 0000000..4004ab7 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/postgresql/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "postgres" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/postgresql/monitors-postgresql.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/postgresql/monitors-postgresql.tf new file mode 100755 index 0000000..ce03d16 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/postgresql/monitors-postgresql.tf @@ -0,0 +1,84 @@ +resource "datadog_monitor" "postgresql_availability" { + count = var.postgresql_availability_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] PostgreSQL server does not respond" + message = coalesce(var.postgresql_availability_message, var.message) + type = "service check" + + query = < ${var.postgresql_connection_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.postgresql_connection_threshold_warning + critical = var.postgresql_connection_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:postgres", "resource:postgresql", "team:claranet", "created-by:terraform"], var.postgresql_connection_extra_tags) +} + +resource "datadog_monitor" "postgresql_too_many_locks" { + count = var.postgresql_lock_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] PostgreSQL too many locks {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.postgresql_lock_message, var.message) + type = "query alert" + + query = < ${var.postgresql_lock_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.postgresql_lock_threshold_warning + critical = var.postgresql_lock_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:postgres", "resource:postgresql", "team:claranet", "created-by:terraform"], var.postgresql_lock_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/postgresql/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/postgresql/outputs.tf new file mode 100755 index 0000000..bb81f0b --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/postgresql/outputs.tf @@ -0,0 +1,15 @@ +output "postgresql_availability_id" { + description = "id for monitor postgresql_availability" + value = datadog_monitor.postgresql_availability.*.id +} + +output "postgresql_connection_too_high_id" { + description = "id for monitor postgresql_connection_too_high" + value = datadog_monitor.postgresql_connection_too_high.*.id +} + +output "postgresql_too_many_locks_id" { + description = "id for monitor postgresql_too_many_locks" + value = datadog_monitor.postgresql_too_many_locks.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/postgresql/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/postgresql/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/postgresql/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/proxysql/README.md b/.terraform/modules/datadog-message-alerting-bh-only/database/proxysql/README.md new file mode 100755 index 0000000..9becd38 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/proxysql/README.md @@ -0,0 +1,116 @@ +# DATABASE PROXYSQL DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-database-proxysql" { + source = "claranet/monitors/datadog//database/proxysql" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- ProxySQL Client connections aborted +- ProxySQL Pool connections failure +- ProxySQL Server connections aborted +- ProxySQL Slow queries +- ProxySQL Thread Worker + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.proxysql_client_conn_aborted](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.proxysql_pool_conn_failure](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.proxysql_server_conn_aborted](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.proxysql_slow](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.proxysql_thread_worker](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the metric evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `false` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [proxysql\_client\_conn\_aborted\_enabled](#input\_proxysql\_client\_conn\_aborted\_enabled) | Flag to enable ProxySQL client connections aborted monitor | `string` | `"true"` | no | +| [proxysql\_client\_conn\_aborted\_extra\_tags](#input\_proxysql\_client\_conn\_aborted\_extra\_tags) | Extra tags for ProxySQL client connections aborted monitor | `list(string)` | `[]` | no | +| [proxysql\_client\_conn\_aborted\_message](#input\_proxysql\_client\_conn\_aborted\_message) | Custom message for ProxySQL client connections aborted monitor | `string` | `""` | no | +| [proxysql\_client\_conn\_aborted\_threshold\_critical](#input\_proxysql\_client\_conn\_aborted\_threshold\_critical) | Maximum critical acceptable percent of aborted connects | `number` | `10` | no | +| [proxysql\_client\_conn\_aborted\_threshold\_warning](#input\_proxysql\_client\_conn\_aborted\_threshold\_warning) | Maximum warning acceptable percent of aborted connects | `number` | `1` | no | +| [proxysql\_client\_conn\_aborted\_time\_aggregator](#input\_proxysql\_client\_conn\_aborted\_time\_aggregator) | Monitor time aggregator for ProxySQL client connections aborted monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [proxysql\_client\_conn\_aborted\_timeframe](#input\_proxysql\_client\_conn\_aborted\_timeframe) | Monitor timeframe for ProxySQL client connections aborted monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_10m"` | no | +| [proxysql\_pool\_conn\_failure\_enabled](#input\_proxysql\_pool\_conn\_failure\_enabled) | Flag to enable ProxySQL pool connections failure monitor | `string` | `"true"` | no | +| [proxysql\_pool\_conn\_failure\_extra\_tags](#input\_proxysql\_pool\_conn\_failure\_extra\_tags) | Extra tags for ProxySQL pool connections failure monitor | `list(string)` | `[]` | no | +| [proxysql\_pool\_conn\_failure\_message](#input\_proxysql\_pool\_conn\_failure\_message) | Custom message for ProxySQL pool connections failure monitor | `string` | `""` | no | +| [proxysql\_pool\_conn\_failure\_threshold\_critical](#input\_proxysql\_pool\_conn\_failure\_threshold\_critical) | Maximum critical acceptable of pool connections failure | `number` | `20` | no | +| [proxysql\_pool\_conn\_failure\_threshold\_warning](#input\_proxysql\_pool\_conn\_failure\_threshold\_warning) | Maximum warning acceptable of pool connections failure | `number` | `1` | no | +| [proxysql\_pool\_conn\_failure\_time\_aggregator](#input\_proxysql\_pool\_conn\_failure\_time\_aggregator) | Monitor time aggregator for ProxySQL pool connections failure monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [proxysql\_pool\_conn\_failure\_timeframe](#input\_proxysql\_pool\_conn\_failure\_timeframe) | Monitor timeframe for ProxySQL pool connections failure monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [proxysql\_server\_conn\_aborted\_enabled](#input\_proxysql\_server\_conn\_aborted\_enabled) | Flag to enable ProxySQL server connections aborted monitor | `string` | `"true"` | no | +| [proxysql\_server\_conn\_aborted\_extra\_tags](#input\_proxysql\_server\_conn\_aborted\_extra\_tags) | Extra tags for ProxySQL server connections aborted monitor | `list(string)` | `[]` | no | +| [proxysql\_server\_conn\_aborted\_message](#input\_proxysql\_server\_conn\_aborted\_message) | Custom message for ProxySQL server connections aborted monitor | `string` | `""` | no | +| [proxysql\_server\_conn\_aborted\_threshold\_critical](#input\_proxysql\_server\_conn\_aborted\_threshold\_critical) | Maximum critical acceptable percent of aborted connects | `number` | `10` | no | +| [proxysql\_server\_conn\_aborted\_threshold\_warning](#input\_proxysql\_server\_conn\_aborted\_threshold\_warning) | Maximum warning acceptable percent of aborted connects | `number` | `1` | no | +| [proxysql\_server\_conn\_aborted\_time\_aggregator](#input\_proxysql\_server\_conn\_aborted\_time\_aggregator) | Monitor time aggregator for ProxySQL server connections aborted monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [proxysql\_server\_conn\_aborted\_timeframe](#input\_proxysql\_server\_conn\_aborted\_timeframe) | Monitor timeframe for ProxySQL server connections aborted monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_10m"` | no | +| [proxysql\_slow\_enabled](#input\_proxysql\_slow\_enabled) | Flag to enable ProxySQL slow queries monitor | `string` | `"true"` | no | +| [proxysql\_slow\_extra\_tags](#input\_proxysql\_slow\_extra\_tags) | Extra tags for ProxySQL slow queries monitor | `list(string)` | `[]` | no | +| [proxysql\_slow\_message](#input\_proxysql\_slow\_message) | Custom message for ProxySQL slow queries monitor | `string` | `""` | no | +| [proxysql\_slow\_threshold\_critical](#input\_proxysql\_slow\_threshold\_critical) | Maximum critical acceptable of slow queries | `number` | `20` | no | +| [proxysql\_slow\_threshold\_warning](#input\_proxysql\_slow\_threshold\_warning) | Maximum warning acceptable of slow queries | `number` | `1` | no | +| [proxysql\_slow\_time\_aggregator](#input\_proxysql\_slow\_time\_aggregator) | Monitor time aggregator for ProxySQL slow queries monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [proxysql\_slow\_timeframe](#input\_proxysql\_slow\_timeframe) | Monitor timeframe for ProxySQL slow queries monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [proxysql\_thread\_worker\_enabled](#input\_proxysql\_thread\_worker\_enabled) | Flag to enable ProxySQL thread worker monitor | `string` | `"true"` | no | +| [proxysql\_thread\_worker\_extra\_tags](#input\_proxysql\_thread\_worker\_extra\_tags) | Extra tags for ProxySQL thread worker monitor | `list(string)` | `[]` | no | +| [proxysql\_thread\_worker\_message](#input\_proxysql\_thread\_worker\_message) | Custom message for ProxySQL thread worker monitor | `string` | `""` | no | +| [proxysql\_thread\_worker\_threshold\_critical](#input\_proxysql\_thread\_worker\_threshold\_critical) | Minimum critical acceptable of thread worker running | `number` | `1` | no | +| [proxysql\_thread\_worker\_threshold\_warning](#input\_proxysql\_thread\_worker\_threshold\_warning) | Minimum warning acceptable of thread worker running | `number` | `4` | no | +| [proxysql\_thread\_worker\_time\_aggregator](#input\_proxysql\_thread\_worker\_time\_aggregator) | Monitor time aggregator for ProxySQL thread worker monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [proxysql\_thread\_worker\_timeframe](#input\_proxysql\_thread\_worker\_timeframe) | Monitor timeframe for ProxySQL thread worker monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [proxysql\_client\_conn\_aborted\_id](#output\_proxysql\_client\_conn\_aborted\_id) | id for monitor proxysql\_client\_conn\_aborted | +| [proxysql\_pool\_conn\_failure\_id](#output\_proxysql\_pool\_conn\_failure\_id) | id for monitor proxysql\_pool\_conn\_failure | +| [proxysql\_server\_conn\_aborted\_id](#output\_proxysql\_server\_conn\_aborted\_id) | id for monitor proxysql\_server\_conn\_aborted | +| [proxysql\_slow\_id](#output\_proxysql\_slow\_id) | id for monitor proxysql\_slow | +| [proxysql\_thread\_worker\_id](#output\_proxysql\_thread\_worker\_id) | id for monitor proxysql\_thread\_worker | +## Related documentation + +* [Datadog documentation](https://docs.datadoghq.com/integrations/proxysql/) +* [ProxySQL documentation](https://proxysql.com/documentation/) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/proxysql/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/proxysql/inputs.tf new file mode 100755 index 0000000..7314488 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/proxysql/inputs.tf @@ -0,0 +1,266 @@ +variable "environment" { + description = "Environment" + type = string +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds for the metric evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = false +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# ProxySQL specific + +################################## +### ProxySQL thread worker ### +################################## + +variable "proxysql_thread_worker_enabled" { + description = "Flag to enable ProxySQL thread worker monitor" + type = string + default = "true" +} + +variable "proxysql_thread_worker_extra_tags" { + description = "Extra tags for ProxySQL thread worker monitor" + type = list(string) + default = [] +} + +variable "proxysql_thread_worker_message" { + description = "Custom message for ProxySQL thread worker monitor" + type = string + default = "" +} + +variable "proxysql_thread_worker_threshold_critical" { + description = "Minimum critical acceptable of thread worker running" + default = 1 +} + +variable "proxysql_thread_worker_threshold_warning" { + description = "Minimum warning acceptable of thread worker running" + default = 4 +} + +variable "proxysql_thread_worker_time_aggregator" { + description = "Monitor time aggregator for ProxySQL thread worker monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "proxysql_thread_worker_timeframe" { + description = "Monitor timeframe for ProxySQL thread worker monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +################################# +### ProxySQL slow queries ### +################################# + +variable "proxysql_slow_enabled" { + description = "Flag to enable ProxySQL slow queries monitor" + type = string + default = "true" +} + +variable "proxysql_slow_extra_tags" { + description = "Extra tags for ProxySQL slow queries monitor" + type = list(string) + default = [] +} + +variable "proxysql_slow_message" { + description = "Custom message for ProxySQL slow queries monitor" + type = string + default = "" +} + +variable "proxysql_slow_threshold_critical" { + description = "Maximum critical acceptable of slow queries" + default = 20 +} + +variable "proxysql_slow_threshold_warning" { + description = "Maximum warning acceptable of slow queries" + default = 1 +} + +variable "proxysql_slow_time_aggregator" { + description = "Monitor time aggregator for ProxySQL slow queries monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "proxysql_slow_timeframe" { + description = "Monitor timeframe for ProxySQL slow queries monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +########################################## +### ProxySQL Client aborted connects ### +########################################## + +variable "proxysql_client_conn_aborted_enabled" { + description = "Flag to enable ProxySQL client connections aborted monitor" + type = string + default = "true" +} + +variable "proxysql_client_conn_aborted_extra_tags" { + description = "Extra tags for ProxySQL client connections aborted monitor" + type = list(string) + default = [] +} + +variable "proxysql_client_conn_aborted_message" { + description = "Custom message for ProxySQL client connections aborted monitor" + type = string + default = "" +} + +variable "proxysql_client_conn_aborted_threshold_critical" { + description = "Maximum critical acceptable percent of aborted connects" + default = 10 +} + +variable "proxysql_client_conn_aborted_threshold_warning" { + description = "Maximum warning acceptable percent of aborted connects" + default = 1 +} + +variable "proxysql_client_conn_aborted_time_aggregator" { + description = "Monitor time aggregator for ProxySQL client connections aborted monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "proxysql_client_conn_aborted_timeframe" { + description = "Monitor timeframe for ProxySQL client connections aborted monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_10m" +} + +########################################## +### ProxySQL Server aborted connects ### +########################################## + +variable "proxysql_server_conn_aborted_enabled" { + description = "Flag to enable ProxySQL server connections aborted monitor" + type = string + default = "true" +} + +variable "proxysql_server_conn_aborted_extra_tags" { + description = "Extra tags for ProxySQL server connections aborted monitor" + type = list(string) + default = [] +} + +variable "proxysql_server_conn_aborted_message" { + description = "Custom message for ProxySQL server connections aborted monitor" + type = string + default = "" +} + +variable "proxysql_server_conn_aborted_threshold_critical" { + description = "Maximum critical acceptable percent of aborted connects" + default = 10 +} + +variable "proxysql_server_conn_aborted_threshold_warning" { + description = "Maximum warning acceptable percent of aborted connects" + default = 1 +} + +variable "proxysql_server_conn_aborted_time_aggregator" { + description = "Monitor time aggregator for ProxySQL server connections aborted monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "proxysql_server_conn_aborted_timeframe" { + description = "Monitor timeframe for ProxySQL server connections aborted monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_10m" +} + + +########################################## +### ProxySQL Pool Connection Failure ### +########################################## + +variable "proxysql_pool_conn_failure_enabled" { + description = "Flag to enable ProxySQL pool connections failure monitor" + type = string + default = "true" +} + +variable "proxysql_pool_conn_failure_extra_tags" { + description = "Extra tags for ProxySQL pool connections failure monitor" + type = list(string) + default = [] +} + +variable "proxysql_pool_conn_failure_message" { + description = "Custom message for ProxySQL pool connections failure monitor" + type = string + default = "" +} + +variable "proxysql_pool_conn_failure_threshold_critical" { + description = "Maximum critical acceptable of pool connections failure" + default = 20 +} + +variable "proxysql_pool_conn_failure_threshold_warning" { + description = "Maximum warning acceptable of pool connections failure" + default = 1 +} + +variable "proxysql_pool_conn_failure_time_aggregator" { + description = "Monitor time aggregator for ProxySQL pool connections failure monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "proxysql_pool_conn_failure_timeframe" { + description = "Monitor timeframe for ProxySQL pool connections failure monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/proxysql/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/proxysql/modules.tf new file mode 100755 index 0000000..ac04d58 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/proxysql/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "proxysql" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/proxysql/monitors-proxysql.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/proxysql/monitors-proxysql.tf new file mode 100755 index 0000000..471721d --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/proxysql/monitors-proxysql.tf @@ -0,0 +1,134 @@ +resource "datadog_monitor" "proxysql_thread_worker" { + count = var.proxysql_thread_worker_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ProxySQL Thread Worker {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.proxysql_thread_worker_message, var.message) + type = "query alert" + + query = < ${var.proxysql_slow_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.proxysql_slow_threshold_warning + critical = var.proxysql_slow_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:proxysql", "resource:proxysql", "team:claranet", "created-by:terraform"], var.proxysql_slow_extra_tags) +} + +resource "datadog_monitor" "proxysql_client_conn_aborted" { + count = var.proxysql_client_conn_aborted_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ProxySQL Client connections aborted {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.proxysql_client_conn_aborted_message, var.message) + type = "query alert" + + query = < ${var.proxysql_client_conn_aborted_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.proxysql_client_conn_aborted_threshold_warning + critical = var.proxysql_client_conn_aborted_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:proxysql", "resource:proxysql", "team:claranet", "created-by:terraform"], var.proxysql_client_conn_aborted_extra_tags) +} + +resource "datadog_monitor" "proxysql_server_conn_aborted" { + count = var.proxysql_server_conn_aborted_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ProxySQL Server connections aborted {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.proxysql_server_conn_aborted_message, var.message) + type = "query alert" + + query = < ${var.proxysql_server_conn_aborted_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.proxysql_server_conn_aborted_threshold_warning + critical = var.proxysql_server_conn_aborted_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:proxysql", "resource:proxysql", "team:claranet", "created-by:terraform"], var.proxysql_server_conn_aborted_extra_tags) +} + +resource "datadog_monitor" "proxysql_pool_conn_failure" { + count = var.proxysql_pool_conn_failure_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ProxySQL Pool connections failure {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.proxysql_pool_conn_failure_message, var.message) + type = "query alert" + + query = < ${var.proxysql_pool_conn_failure_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.proxysql_pool_conn_failure_threshold_warning + critical = var.proxysql_pool_conn_failure_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:proxysql", "resource:proxysql", "team:claranet", "created-by:terraform"], var.proxysql_pool_conn_failure_extra_tags) +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/proxysql/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/proxysql/outputs.tf new file mode 100755 index 0000000..665c7d3 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/proxysql/outputs.tf @@ -0,0 +1,25 @@ +output "proxysql_client_conn_aborted_id" { + description = "id for monitor proxysql_client_conn_aborted" + value = datadog_monitor.proxysql_client_conn_aborted.*.id +} + +output "proxysql_pool_conn_failure_id" { + description = "id for monitor proxysql_pool_conn_failure" + value = datadog_monitor.proxysql_pool_conn_failure.*.id +} + +output "proxysql_server_conn_aborted_id" { + description = "id for monitor proxysql_server_conn_aborted" + value = datadog_monitor.proxysql_server_conn_aborted.*.id +} + +output "proxysql_slow_id" { + description = "id for monitor proxysql_slow" + value = datadog_monitor.proxysql_slow.*.id +} + +output "proxysql_thread_worker_id" { + description = "id for monitor proxysql_thread_worker" + value = datadog_monitor.proxysql_thread_worker.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/proxysql/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/proxysql/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/proxysql/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/redis/README.md b/.terraform/modules/datadog-message-alerting-bh-only/database/redis/README.md new file mode 100755 index 0000000..c81e648 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/redis/README.md @@ -0,0 +1,165 @@ +# DATABASE REDIS DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-database-redis" { + source = "claranet/monitors/datadog//database/redis" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Redis blocked clients +- Redis does not respond +- Redis evicted keys +- Redis expired keys +- Redis hitrate +- Redis keyspace seems full (no changes since ${var.keyspace_timeframe}) +- Redis latency +- Redis memory fragmented +- Redis memory used +- Redis rejected connections + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.blocked_clients](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.evicted_keys](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.expirations](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.hitrate](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.keyspace_full](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.memory_frag](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.memory_used](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.not_responding](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.rejected_connections](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [blocked\_clients\_enabled](#input\_blocked\_clients\_enabled) | Flag to enable Redis Blocked clients monitor | `string` | `"true"` | no | +| [blocked\_clients\_extra\_tags](#input\_blocked\_clients\_extra\_tags) | Extra tags for Redis Blocked clients monitor | `list(string)` | `[]` | no | +| [blocked\_clients\_message](#input\_blocked\_clients\_message) | Custom message for Redis Blocked clients monitor | `string` | `""` | no | +| [blocked\_clients\_threshold\_critical](#input\_blocked\_clients\_threshold\_critical) | Blocked clients rate (critical threshold) | `number` | `30` | no | +| [blocked\_clients\_threshold\_warning](#input\_blocked\_clients\_threshold\_warning) | Blocked clients rate (warning threshold) | `number` | `10` | no | +| [blocked\_clients\_time\_aggregator](#input\_blocked\_clients\_time\_aggregator) | Monitor aggregator for Redis Blocked clients [available values: min, max or avg] | `string` | `"min"` | no | +| [blocked\_clients\_timeframe](#input\_blocked\_clients\_timeframe) | Monitor timeframe for Redis Blocked clients [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [evictedkeys\_change\_enabled](#input\_evictedkeys\_change\_enabled) | Flag to enable Redis evicted keys monitor | `string` | `"true"` | no | +| [evictedkeys\_change\_extra\_tags](#input\_evictedkeys\_change\_extra\_tags) | Extra tags for Redis evicted keys monitor | `list(string)` | `[]` | no | +| [evictedkeys\_change\_message](#input\_evictedkeys\_change\_message) | Custom message for Redis evicted keys monitor | `string` | `""` | no | +| [evictedkeys\_change\_threshold\_critical](#input\_evictedkeys\_change\_threshold\_critical) | Evicted keys change (critical threshold) | `number` | `100` | no | +| [evictedkeys\_change\_threshold\_warning](#input\_evictedkeys\_change\_threshold\_warning) | Evicted keys change (warning threshold) | `number` | `20` | no | +| [evictedkeys\_change\_time\_aggregator](#input\_evictedkeys\_change\_time\_aggregator) | Monitor aggregator for Redis evicted keys [available values: min, max or avg] | `string` | `"avg"` | no | +| [evictedkeys\_change\_timeframe](#input\_evictedkeys\_change\_timeframe) | Monitor timeframe for Redis evicted keys [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [expirations\_rate\_enabled](#input\_expirations\_rate\_enabled) | Flag to enable Redis keys expirations monitor | `string` | `"true"` | no | +| [expirations\_rate\_extra\_tags](#input\_expirations\_rate\_extra\_tags) | Extra tags for Redis keys expirations monitor | `list(string)` | `[]` | no | +| [expirations\_rate\_message](#input\_expirations\_rate\_message) | Custom message for Redis keys expirations monitor | `string` | `""` | no | +| [expirations\_rate\_threshold\_critical](#input\_expirations\_rate\_threshold\_critical) | Expirations percent (critical threshold) | `number` | `80` | no | +| [expirations\_rate\_threshold\_warning](#input\_expirations\_rate\_threshold\_warning) | Expirations percent (warning threshold) | `number` | `60` | no | +| [expirations\_rate\_time\_aggregator](#input\_expirations\_rate\_time\_aggregator) | Monitor aggregator for Redis keys expirations [available values: min, max or avg] | `string` | `"min"` | no | +| [expirations\_rate\_timeframe](#input\_expirations\_rate\_timeframe) | Monitor timeframe for Redis keys expirations [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [hitrate\_enabled](#input\_hitrate\_enabled) | Flag to enable Redis hitrate monitor | `string` | `"true"` | no | +| [hitrate\_extra\_tags](#input\_hitrate\_extra\_tags) | Extra tags for Redis hitrate monitor | `list(string)` | `[]` | no | +| [hitrate\_message](#input\_hitrate\_message) | Custom message for Redis hitrate monitor | `string` | `""` | no | +| [hitrate\_threshold\_critical](#input\_hitrate\_threshold\_critical) | hitrate limit (critical threshold) | `number` | `10` | no | +| [hitrate\_threshold\_warning](#input\_hitrate\_threshold\_warning) | hitrate limit (warning threshold) | `number` | `30` | no | +| [hitrate\_time\_aggregator](#input\_hitrate\_time\_aggregator) | Monitor aggregator for Redis hitrate [available values: min, max or avg] | `string` | `"max"` | no | +| [hitrate\_timeframe](#input\_hitrate\_timeframe) | Monitor timeframe for Redis hitrate [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [keyspace\_enabled](#input\_keyspace\_enabled) | Flag to enable Redis keyspace monitor | `string` | `"true"` | no | +| [keyspace\_extra\_tags](#input\_keyspace\_extra\_tags) | Extra tags for Redis keyspace monitor | `list(string)` | `[]` | no | +| [keyspace\_message](#input\_keyspace\_message) | Custom message for Redis keyspace monitor | `string` | `""` | no | +| [keyspace\_threshold\_critical](#input\_keyspace\_threshold\_critical) | Keyspace no changement (critical threshold) | `number` | `0` | no | +| [keyspace\_threshold\_warning](#input\_keyspace\_threshold\_warning) | Keyspace no changement (warning threshold) | `number` | `1` | no | +| [keyspace\_time\_aggregator](#input\_keyspace\_time\_aggregator) | Monitor aggregator for Redis keyspace [available values: min, max or avg] | `string` | `"min"` | no | +| [keyspace\_timeframe](#input\_keyspace\_timeframe) | Monitor timeframe for Redis keyspace [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [latency\_enabled](#input\_latency\_enabled) | Flag to enable Redis latency monitor | `string` | `"true"` | no | +| [latency\_extra\_tags](#input\_latency\_extra\_tags) | Extra tags for Redis latency monitor | `list(string)` | `[]` | no | +| [latency\_message](#input\_latency\_message) | Custom message for Redis latency monitor | `string` | `""` | no | +| [latency\_threshold\_critical](#input\_latency\_threshold\_critical) | latency limit (critical threshold) | `number` | `100` | no | +| [latency\_threshold\_warning](#input\_latency\_threshold\_warning) | latency limit (warning threshold) | `number` | `50` | no | +| [latency\_time\_aggregator](#input\_latency\_time\_aggregator) | Monitor aggregator for Redis latency [available values: min, max or avg] | `string` | `"min"` | no | +| [latency\_timeframe](#input\_latency\_timeframe) | Monitor timeframe for Redis latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [mem\_frag\_enabled](#input\_mem\_frag\_enabled) | Flag to enable Redis memory RAM fragmentation monitor | `string` | `"true"` | no | +| [mem\_frag\_extra\_tags](#input\_mem\_frag\_extra\_tags) | Extra tags for Redis memory RAM fragmentation monitor | `list(string)` | `[]` | no | +| [mem\_frag\_message](#input\_mem\_frag\_message) | Custom message for Redis memory RAM fragmentation monitor | `string` | `""` | no | +| [mem\_frag\_threshold\_critical](#input\_mem\_frag\_threshold\_critical) | memory RAM fragmentation limit (critical threshold) | `number` | `150` | no | +| [mem\_frag\_threshold\_warning](#input\_mem\_frag\_threshold\_warning) | memory RAM fragmentation limit (warning threshold) | `number` | `130` | no | +| [mem\_frag\_time\_aggregator](#input\_mem\_frag\_time\_aggregator) | Monitor aggregator for Redis memory RAM fragmentation [available values: min, max or avg] | `string` | `"min"` | no | +| [mem\_frag\_timeframe](#input\_mem\_frag\_timeframe) | Monitor timeframe for Redis memory RAM fragmentation [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [mem\_used\_enabled](#input\_mem\_used\_enabled) | Flag to enable Redis RAM memory used monitor | `string` | `"true"` | no | +| [mem\_used\_extra\_tags](#input\_mem\_used\_extra\_tags) | Extra tags for Redis RAM memory used monitor | `list(string)` | `[]` | no | +| [mem\_used\_message](#input\_mem\_used\_message) | Custom message for Redis RAM memory used monitor | `string` | `""` | no | +| [mem\_used\_threshold\_critical](#input\_mem\_used\_threshold\_critical) | RAM memory used limit (critical threshold) | `number` | `95` | no | +| [mem\_used\_threshold\_warning](#input\_mem\_used\_threshold\_warning) | RAM memory used limit (warning threshold) | `number` | `85` | no | +| [mem\_used\_time\_aggregator](#input\_mem\_used\_time\_aggregator) | Monitor aggregator for Redis RAM memory used [available values: min, max or avg] | `string` | `"min"` | no | +| [mem\_used\_timeframe](#input\_mem\_used\_timeframe) | Monitor timeframe for Redis RAM memory used [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when a Redis monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the metric evaluation | `number` | `300` | no | +| [not\_responding\_enabled](#input\_not\_responding\_enabled) | Flag to enable Redis does not respond monitor | `string` | `"true"` | no | +| [not\_responding\_extra\_tags](#input\_not\_responding\_extra\_tags) | Extra tags for Redis does not respond monitor | `list(string)` | `[]` | no | +| [not\_responding\_message](#input\_not\_responding\_message) | Custom message for Redis does not respond monitor | `string` | `""` | no | +| [not\_responding\_no\_data\_timeframe](#input\_not\_responding\_no\_data\_timeframe) | Redis does not respond monitor no data timeframe | `string` | `10` | no | +| [not\_responding\_threshold\_warning](#input\_not\_responding\_threshold\_warning) | Redis does not respond monitor (warning threshold) | `string` | `3` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [rejected\_con\_enabled](#input\_rejected\_con\_enabled) | Flag to enable Redis rejected connections errors monitor | `string` | `"true"` | no | +| [rejected\_con\_extra\_tags](#input\_rejected\_con\_extra\_tags) | Extra tags for Redis rejected connections errors monitor | `list(string)` | `[]` | no | +| [rejected\_con\_message](#input\_rejected\_con\_message) | Custom message for Redis rejected connections errors monitor | `string` | `""` | no | +| [rejected\_con\_threshold\_critical](#input\_rejected\_con\_threshold\_critical) | rejected connections errors limit (critical threshold) | `number` | `50` | no | +| [rejected\_con\_threshold\_warning](#input\_rejected\_con\_threshold\_warning) | rejected connections errors limit (warning threshold) | `number` | `10` | no | +| [rejected\_con\_time\_aggregator](#input\_rejected\_con\_time\_aggregator) | Monitor aggregator for Redis rejected connections errors [available values: min, max or avg] | `string` | `"min"` | no | +| [rejected\_con\_timeframe](#input\_rejected\_con\_timeframe) | Monitor timeframe for Redis rejected connections errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [blocked\_clients\_id](#output\_blocked\_clients\_id) | id for monitor blocked\_clients | +| [evicted\_keys\_id](#output\_evicted\_keys\_id) | id for monitor evicted\_keys | +| [expirations\_id](#output\_expirations\_id) | id for monitor expirations | +| [hitrate\_id](#output\_hitrate\_id) | id for monitor hitrate | +| [keyspace\_full\_id](#output\_keyspace\_full\_id) | id for monitor keyspace\_full | +| [latency\_id](#output\_latency\_id) | id for monitor latency | +| [memory\_frag\_id](#output\_memory\_frag\_id) | id for monitor memory\_frag | +| [memory\_used\_id](#output\_memory\_used\_id) | id for monitor memory\_used | +| [not\_responding\_id](#output\_not\_responding\_id) | id for monitor not\_responding | +| [rejected\_connections\_id](#output\_rejected\_connections\_id) | id for monitor rejected\_connections | +## Related documentation + +[Datadog blog: How to monitor Redis](https://www.datadoghq.com/blog/how-to-monitor-redis-performance-metrics/) + +[Datadog Redis integration doc](https://docs.datadoghq.com/integrations/redisdb/) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/redis/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/redis/inputs.tf new file mode 100755 index 0000000..e8ac16b --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/redis/inputs.tf @@ -0,0 +1,442 @@ +# Global Terraform +variable "environment" { + description = "Architecture environment" + type = string +} + +# Global DataDog +variable "message" { + description = "Message sent when a Redis monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds for the metric evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Redis specific variables + +variable "evictedkeys_change_enabled" { + description = "Flag to enable Redis evicted keys monitor" + type = string + default = "true" +} + +variable "evictedkeys_change_message" { + description = "Custom message for Redis evicted keys monitor" + type = string + default = "" +} + +variable "evictedkeys_change_extra_tags" { + description = "Extra tags for Redis evicted keys monitor" + type = list(string) + default = [] +} + +variable "evictedkeys_change_time_aggregator" { + description = "Monitor aggregator for Redis evicted keys [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "evictedkeys_change_timeframe" { + description = "Monitor timeframe for Redis evicted keys [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "evictedkeys_change_threshold_warning" { + description = "Evicted keys change (warning threshold)" + default = 20 +} + +variable "evictedkeys_change_threshold_critical" { + description = "Evicted keys change (critical threshold)" + default = 100 +} + +variable "expirations_rate_enabled" { + description = "Flag to enable Redis keys expirations monitor" + type = string + default = "true" +} + +variable "expirations_rate_message" { + description = "Custom message for Redis keys expirations monitor" + type = string + default = "" +} + +variable "expirations_rate_extra_tags" { + description = "Extra tags for Redis keys expirations monitor" + type = list(string) + default = [] +} + +variable "expirations_rate_time_aggregator" { + description = "Monitor aggregator for Redis keys expirations [available values: min, max or avg]" + type = string + default = "min" +} + +variable "expirations_rate_timeframe" { + description = "Monitor timeframe for Redis keys expirations [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "expirations_rate_threshold_critical" { + description = "Expirations percent (critical threshold)" + default = 80 +} + +variable "expirations_rate_threshold_warning" { + description = "Expirations percent (warning threshold)" + default = 60 +} + +variable "blocked_clients_enabled" { + description = "Flag to enable Redis Blocked clients monitor" + type = string + default = "true" +} + +variable "blocked_clients_message" { + description = "Custom message for Redis Blocked clients monitor" + type = string + default = "" +} + +variable "blocked_clients_extra_tags" { + description = "Extra tags for Redis Blocked clients monitor" + type = list(string) + default = [] +} + +variable "blocked_clients_time_aggregator" { + description = "Monitor aggregator for Redis Blocked clients [available values: min, max or avg]" + type = string + default = "min" +} + +variable "blocked_clients_timeframe" { + description = "Monitor timeframe for Redis Blocked clients [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "blocked_clients_threshold_critical" { + description = "Blocked clients rate (critical threshold)" + default = 30 +} + +variable "blocked_clients_threshold_warning" { + description = "Blocked clients rate (warning threshold)" + default = 10 +} + +variable "keyspace_enabled" { + description = "Flag to enable Redis keyspace monitor" + type = string + default = "true" +} + +variable "keyspace_message" { + description = "Custom message for Redis keyspace monitor" + type = string + default = "" +} + +variable "keyspace_extra_tags" { + description = "Extra tags for Redis keyspace monitor" + type = list(string) + default = [] +} + +variable "keyspace_time_aggregator" { + description = "Monitor aggregator for Redis keyspace [available values: min, max or avg]" + type = string + default = "min" +} + +variable "keyspace_timeframe" { + description = "Monitor timeframe for Redis keyspace [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "keyspace_threshold_critical" { + description = "Keyspace no changement (critical threshold)" + default = 0 +} + +variable "keyspace_threshold_warning" { + description = "Keyspace no changement (warning threshold)" + default = 1 +} + +variable "mem_used_enabled" { + description = "Flag to enable Redis RAM memory used monitor" + type = string + default = "true" +} + +variable "mem_used_message" { + description = "Custom message for Redis RAM memory used monitor" + type = string + default = "" +} + +variable "mem_used_extra_tags" { + description = "Extra tags for Redis RAM memory used monitor" + type = list(string) + default = [] +} + +variable "mem_used_time_aggregator" { + description = "Monitor aggregator for Redis RAM memory used [available values: min, max or avg]" + type = string + default = "min" +} + +variable "mem_used_timeframe" { + description = "Monitor timeframe for Redis RAM memory used [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "mem_used_threshold_critical" { + description = "RAM memory used limit (critical threshold)" + default = 95 +} + +variable "mem_used_threshold_warning" { + description = "RAM memory used limit (warning threshold)" + default = 85 +} + +variable "mem_frag_enabled" { + description = "Flag to enable Redis memory RAM fragmentation monitor" + type = string + default = "true" +} + +variable "mem_frag_message" { + description = "Custom message for Redis memory RAM fragmentation monitor" + type = string + default = "" +} + +variable "mem_frag_extra_tags" { + description = "Extra tags for Redis memory RAM fragmentation monitor" + type = list(string) + default = [] +} + +variable "mem_frag_time_aggregator" { + description = "Monitor aggregator for Redis memory RAM fragmentation [available values: min, max or avg]" + type = string + default = "min" +} + +variable "mem_frag_timeframe" { + description = "Monitor timeframe for Redis memory RAM fragmentation [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "mem_frag_threshold_critical" { + description = "memory RAM fragmentation limit (critical threshold)" + default = 150 +} + +variable "mem_frag_threshold_warning" { + description = "memory RAM fragmentation limit (warning threshold)" + default = 130 +} + +variable "rejected_con_enabled" { + description = "Flag to enable Redis rejected connections errors monitor" + type = string + default = "true" +} + +variable "rejected_con_message" { + description = "Custom message for Redis rejected connections errors monitor" + type = string + default = "" +} + +variable "rejected_con_extra_tags" { + description = "Extra tags for Redis rejected connections errors monitor" + type = list(string) + default = [] +} + +variable "rejected_con_time_aggregator" { + description = "Monitor aggregator for Redis rejected connections errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "rejected_con_timeframe" { + description = "Monitor timeframe for Redis rejected connections errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "rejected_con_threshold_critical" { + description = "rejected connections errors limit (critical threshold)" + default = 50 +} + +variable "rejected_con_threshold_warning" { + description = "rejected connections errors limit (warning threshold)" + default = 10 +} + +variable "latency_enabled" { + description = "Flag to enable Redis latency monitor" + type = string + default = "true" +} + +variable "latency_message" { + description = "Custom message for Redis latency monitor" + type = string + default = "" +} + +variable "latency_extra_tags" { + description = "Extra tags for Redis latency monitor" + type = list(string) + default = [] +} + +variable "latency_time_aggregator" { + description = "Monitor aggregator for Redis latency [available values: min, max or avg]" + type = string + default = "min" +} + +variable "latency_timeframe" { + description = "Monitor timeframe for Redis latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "latency_threshold_critical" { + description = "latency limit (critical threshold)" + default = 100 +} + +variable "latency_threshold_warning" { + description = "latency limit (warning threshold)" + default = 50 +} + +variable "hitrate_enabled" { + description = "Flag to enable Redis hitrate monitor" + type = string + default = "true" +} + +variable "hitrate_message" { + description = "Custom message for Redis hitrate monitor" + type = string + default = "" +} + +variable "hitrate_extra_tags" { + description = "Extra tags for Redis hitrate monitor" + type = list(string) + default = [] +} + +variable "hitrate_time_aggregator" { + description = "Monitor aggregator for Redis hitrate [available values: min, max or avg]" + type = string + default = "max" +} + +variable "hitrate_timeframe" { + description = "Monitor timeframe for Redis hitrate [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "hitrate_threshold_critical" { + description = "hitrate limit (critical threshold)" + default = 10 +} + +variable "hitrate_threshold_warning" { + description = "hitrate limit (warning threshold)" + default = 30 +} + +# +# Connection Down +# + +variable "not_responding_enabled" { + description = "Flag to enable Redis does not respond monitor" + type = string + default = "true" +} + +variable "not_responding_message" { + description = "Custom message for Redis does not respond monitor" + type = string + default = "" +} + +variable "not_responding_extra_tags" { + description = "Extra tags for Redis does not respond monitor" + type = list(string) + default = [] +} + +variable "not_responding_threshold_warning" { + description = "Redis does not respond monitor (warning threshold)" + type = string + default = 3 +} + +variable "not_responding_no_data_timeframe" { + description = "Redis does not respond monitor no data timeframe" + type = string + default = 10 +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/redis/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/redis/modules.tf new file mode 100755 index 0000000..f923fe0 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/redis/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "redis" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/redis/monitors-redis.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/redis/monitors-redis.tf new file mode 100755 index 0000000..a05455b --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/redis/monitors-redis.tf @@ -0,0 +1,305 @@ +# +# Service Check +# +resource "datadog_monitor" "not_responding" { + count = var.not_responding_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Redis does not respond" + message = coalesce(var.not_responding_message, var.message) + type = "service check" + + query = < ${var.evictedkeys_change_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.evictedkeys_change_threshold_warning + critical = var.evictedkeys_change_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:database", "provider:redisdb", "resource:redis", "team:claranet", "created-by:terraform"], var.evictedkeys_change_extra_tags) +} + +resource "datadog_monitor" "expirations" { + count = var.expirations_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Redis expired keys {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.expirations_rate_message, var.message) + type = "query alert" + + query = < ${var.expirations_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.expirations_rate_threshold_warning + critical = var.expirations_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:database", "provider:redisdb", "resource:redis", "team:claranet", "created-by:terraform"], var.expirations_rate_extra_tags) +} + +resource "datadog_monitor" "blocked_clients" { + count = var.blocked_clients_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Redis blocked clients {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.blocked_clients_message, var.message) + type = "query alert" + + query = < ${var.blocked_clients_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.blocked_clients_threshold_warning + critical = var.blocked_clients_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:database", "provider:redisdb", "resource:redis", "team:claranet", "created-by:terraform"], var.blocked_clients_extra_tags) +} + +resource "datadog_monitor" "keyspace_full" { + count = var.keyspace_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Redis keyspace seems full (no changes since ${var.keyspace_timeframe})" + message = coalesce(var.keyspace_message, var.message) + type = "query alert" + + query = < ${var.mem_used_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.mem_used_threshold_warning + critical = var.mem_used_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:database", "provider:redisdb", "resource:redis", "team:claranet", "created-by:terraform"], var.mem_used_extra_tags) +} + +resource "datadog_monitor" "memory_frag" { + count = var.mem_frag_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Redis memory fragmented {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.mem_frag_message, var.message) + type = "query alert" + + query = < ${var.mem_frag_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.mem_frag_threshold_warning + critical = var.mem_frag_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:database", "provider:redisdb", "resource:redis", "team:claranet", "created-by:terraform"], var.mem_frag_extra_tags) +} + +resource "datadog_monitor" "rejected_connections" { + count = var.rejected_con_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Redis rejected connections {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.rejected_con_message, var.message) + type = "query alert" + + query = < ${var.rejected_con_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.rejected_con_threshold_warning + critical = var.rejected_con_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:database", "provider:redisdb", "resource:redis", "team:claranet", "created-by:terraform"], var.rejected_con_extra_tags) +} + +resource "datadog_monitor" "latency" { + count = var.latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Redis latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}){{/is_warning}}" + message = coalesce(var.latency_message, var.message) + type = "query alert" + + query = < ${var.latency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.latency_threshold_warning + critical = var.latency_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:database", "provider:redisdb", "resource:redis", "team:claranet", "created-by:terraform"], var.latency_extra_tags) +} + +resource "datadog_monitor" "hitrate" { + count = var.hitrate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Redis hitrate {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.hitrate_message, var.message) + type = "query alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.not_responding](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.search_handler_errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.searcher_warmup_time](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before begin to monitor new host | `number` | `300` | no | +| [not\_responding\_enabled](#input\_not\_responding\_enabled) | Flag to enable Solr does not repsond monitor | `bool` | `true` | no | +| [not\_responding\_extra\_tags](#input\_not\_responding\_extra\_tags) | Extra tags for solr does not respond monitor | `list(string)` | `[]` | no | +| [not\_responding\_group\_by](#input\_not\_responding\_group\_by) | Not responding tags to group data | `list(string)` |
[
"instance"
]
| no | +| [not\_responding\_message](#input\_not\_responding\_message) | Custom message for Solr does not respond monitor | `string` | `""` | no | +| [not\_responding\_no\_data\_timeframe](#input\_not\_responding\_no\_data\_timeframe) | Solr not responding monitor no data timeframe | `number` | `10` | no | +| [not\_responding\_threshold\_warning](#input\_not\_responding\_threshold\_warning) | Solr not responding limit (warning threshold) | `number` | `3` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [search\_handler\_errors\_enabled](#input\_search\_handler\_errors\_enabled) | Flag to enable Solr search handler errors monitor | `bool` | `true` | no | +| [search\_handler\_errors\_extra\_tags](#input\_search\_handler\_errors\_extra\_tags) | Extra tags for Search handler errors monitor | `list(string)` | `[]` | no | +| [search\_handler\_errors\_group\_by](#input\_search\_handler\_errors\_group\_by) | Search handler errors tags to group datas | `list(string)` |
[
"instance"
]
| no | +| [search\_handler\_errors\_message](#input\_search\_handler\_errors\_message) | Custom message for Solr search handler errors monitor | `string` | `""` | no | +| [search\_handler\_errors\_rate\_threshold\_critical](#input\_search\_handler\_errors\_rate\_threshold\_critical) | Handler errors rate critical threshold | `number` | `50` | no | +| [search\_handler\_errors\_rate\_threshold\_warning](#input\_search\_handler\_errors\_rate\_threshold\_warning) | Handler errors rate warning threshold | `number` | `10` | no | +| [search\_handler\_errors\_time\_aggregator](#input\_search\_handler\_errors\_time\_aggregator) | Time aggregator for the Handler errors monitor | `string` | `"min"` | no | +| [search\_handler\_errors\_timeframe](#input\_search\_handler\_errors\_timeframe) | Timeframe for the search handler errors monitor | `string` | `"last_5m"` | no | +| [searcher\_warmup\_time\_aggregator](#input\_searcher\_warmup\_time\_aggregator) | Time aggregator for the searcher warmup time monitor | `string` | `"max"` | no | +| [searcher\_warmup\_time\_enabled](#input\_searcher\_warmup\_time\_enabled) | Flag to enable Solr searcher warmup time monitor | `bool` | `true` | no | +| [searcher\_warmup\_time\_extra\_tags](#input\_searcher\_warmup\_time\_extra\_tags) | Extra tags for searcher warmum time monitor | `list(string)` | `[]` | no | +| [searcher\_warmup\_time\_group\_by](#input\_searcher\_warmup\_time\_group\_by) | Search warmup time tags to group datas | `list(string)` |
[
"instance"
]
| no | +| [searcher\_warmup\_time\_message](#input\_searcher\_warmup\_time\_message) | Custom message for Solr searcher warmup time monitor | `string` | `""` | no | +| [searcher\_warmup\_time\_threshold\_critical](#input\_searcher\_warmup\_time\_threshold\_critical) | Searcher warmup time critical threshold in ms | `number` | `5000` | no | +| [searcher\_warmup\_time\_threshold\_warning](#input\_searcher\_warmup\_time\_threshold\_warning) | Searcher warmup time warning threshold in ms | `number` | `2000` | no | +| [searcher\_warmup\_time\_timeframe](#input\_searcher\_warmup\_time\_timeframe) | Timeframe for the searcher warmup time monitor | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [not\_responding\_id](#output\_not\_responding\_id) | id for monitor not\_responding | +| [search\_handler\_errors\_id](#output\_search\_handler\_errors\_id) | id for monitor search\_handler\_errors | +| [searcher\_warmup\_time\_id](#output\_searcher\_warmup\_time\_id) | id for monitor searcher\_warmup\_time | +## Related documentation + + - [Integration Datadog & Solr](https://docs.datadoghq.com/integrations/solr/) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/solr/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/solr/inputs.tf new file mode 100755 index 0000000..9e6ac08 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/solr/inputs.tf @@ -0,0 +1,189 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before begin to monitor new host" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + + +# +# Service Check +# +variable "not_responding_enabled" { + type = bool + description = "Flag to enable Solr does not repsond monitor" + default = true +} + +variable "not_responding_group_by" { + type = list(string) + description = "Not responding tags to group data" + default = ["instance"] +} + +variable "not_responding_message" { + description = "Custom message for Solr does not respond monitor" + type = string + default = "" +} + +variable "not_responding_threshold_warning" { + type = number + default = 3 + description = "Solr not responding limit (warning threshold)" +} + +variable "not_responding_no_data_timeframe" { + description = "Solr not responding monitor no data timeframe" + type = number + default = 10 +} + +variable "not_responding_extra_tags" { + description = "Extra tags for solr does not respond monitor" + type = list(string) + default = [] +} + +# +# Handler errors +# +variable "search_handler_errors_enabled" { + description = "Flag to enable Solr search handler errors monitor" + type = bool + default = true +} + +variable "search_handler_errors_group_by" { + description = "Search handler errors tags to group datas" + type = list(string) + default = ["instance"] +} + +variable "search_handler_errors_message" { + description = "Custom message for Solr search handler errors monitor" + type = string + default = "" +} +variable "search_handler_errors_rate_threshold_critical" { + description = "Handler errors rate critical threshold" + default = 50 + type = number +} + +variable "search_handler_errors_rate_threshold_warning" { + description = "Handler errors rate warning threshold" + default = 10 + type = number +} + +variable "search_handler_errors_time_aggregator" { + description = "Time aggregator for the Handler errors monitor" + type = string + default = "min" +} + +variable "search_handler_errors_timeframe" { + description = "Timeframe for the search handler errors monitor" + type = string + default = "last_5m" +} + +variable "search_handler_errors_extra_tags" { + description = "Extra tags for Search handler errors monitor" + default = [] + type = list(string) +} + +# +# Searcher warmup time +# +variable "searcher_warmup_time_enabled" { + default = true + description = "Flag to enable Solr searcher warmup time monitor" + type = bool +} + +variable "searcher_warmup_time_group_by" { + default = ["instance"] + description = "Search warmup time tags to group datas" + type = list(string) +} + +variable "searcher_warmup_time_message" { + description = "Custom message for Solr searcher warmup time monitor" + default = "" + type = string +} + +variable "searcher_warmup_time_threshold_warning" { + description = "Searcher warmup time warning threshold in ms" + # 2sec + default = 2000 + type = number +} + +variable "searcher_warmup_time_threshold_critical" { + description = "Searcher warmup time critical threshold in ms" + # 5 sec + default = 5000 + type = number +} + +variable "searcher_warmup_time_extra_tags" { + description = "Extra tags for searcher warmum time monitor" + default = [] + type = list(string) +} + +variable "searcher_warmup_time_aggregator" { + description = "Time aggregator for the searcher warmup time monitor" + default = "max" + type = string +} + +variable "searcher_warmup_time_timeframe" { + description = "Timeframe for the searcher warmup time monitor" + default = "last_5m" + type = string +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/solr/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/solr/modules.tf new file mode 100755 index 0000000..ead22a8 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/solr/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "solr" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} \ No newline at end of file diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/solr/monitors-solr.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/solr/monitors-solr.tf new file mode 100755 index 0000000..06b1cef --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/solr/monitors-solr.tf @@ -0,0 +1,97 @@ +# +# Service Check +# + +resource "datadog_monitor" "not_responding" { + count = var.not_responding_enabled ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Solr does not respond {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.not_responding_message, var.message) + type = "service check" + + query = < ${var.search_handler_errors_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.search_handler_errors_rate_threshold_warning + critical = var.search_handler_errors_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:solr", "resource:solr", "team:claranet", "created-by:terraform"], var.search_handler_errors_extra_tags) + +} + +# +# Solr Warmup time +# + +resource "datadog_monitor" "searcher_warmup_time" { + count = var.searcher_warmup_time_enabled ? 1 : 0 + message = coalesce(var.searcher_warmup_time_message, var.message) + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Solr searcher warmup time too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + type = "metric alert" + query = <= ${var.searcher_warmup_time_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.searcher_warmup_time_threshold_warning + critical = var.searcher_warmup_time_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:solr", "resource:solr", "team:claranet", "created-by:terraform"], var.searcher_warmup_time_extra_tags) +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/solr/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/solr/outputs.tf new file mode 100755 index 0000000..cdad6c1 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/solr/outputs.tf @@ -0,0 +1,15 @@ +output "not_responding_id" { + description = "id for monitor not_responding" + value = datadog_monitor.not_responding.*.id +} + +output "search_handler_errors_id" { + description = "id for monitor search_handler_errors" + value = datadog_monitor.search_handler_errors.*.id +} + +output "searcher_warmup_time_id" { + description = "id for monitor searcher_warmup_time" + value = datadog_monitor.searcher_warmup_time.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/solr/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/solr/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/solr/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/sqlserver/README.md b/.terraform/modules/datadog-message-alerting-bh-only/database/sqlserver/README.md new file mode 100755 index 0000000..c78785c --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/sqlserver/README.md @@ -0,0 +1,73 @@ +# DATABASE SQLSERVER DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-database-sqlserver" { + source = "claranet/monitors/datadog//database/sqlserver" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- SQL Server server does not respond + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.sqlserver_availability](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the metric evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [sqlserver\_availability\_enabled](#input\_sqlserver\_availability\_enabled) | Flag to enable SQL Server availability monitor | `string` | `"true"` | no | +| [sqlserver\_availability\_extra\_tags](#input\_sqlserver\_availability\_extra\_tags) | Extra tags for SQL Server availability monitor | `list(string)` | `[]` | no | +| [sqlserver\_availability\_message](#input\_sqlserver\_availability\_message) | Custom message for SQL Server availability monitor | `string` | `""` | no | +| [sqlserver\_availability\_no\_data\_timeframe](#input\_sqlserver\_availability\_no\_data\_timeframe) | SQL Server availability monitor no data timeframe | `string` | `10` | no | +| [sqlserver\_availability\_threshold\_warning](#input\_sqlserver\_availability\_threshold\_warning) | SQL Server availability monitor (warning threshold) | `string` | `3` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [sqlserver\_availability\_id](#output\_sqlserver\_availability\_id) | id for monitor sqlserver\_availability | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/sqlserver/](https://docs.datadoghq.com/integrations/sqlserver/) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/sqlserver/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/sqlserver/inputs.tf new file mode 100755 index 0000000..378a413 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/sqlserver/inputs.tf @@ -0,0 +1,79 @@ +variable "environment" { + description = "Environment" + type = string +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds for the metric evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# SQL Server specific + +################################# +### SQL Server availability ### +################################# + +variable "sqlserver_availability_enabled" { + description = "Flag to enable SQL Server availability monitor" + type = string + default = "true" +} + +variable "sqlserver_availability_extra_tags" { + description = "Extra tags for SQL Server availability monitor" + type = list(string) + default = [] +} + +variable "sqlserver_availability_message" { + description = "Custom message for SQL Server availability monitor" + type = string + default = "" +} + +variable "sqlserver_availability_threshold_warning" { + description = "SQL Server availability monitor (warning threshold)" + type = string + default = 3 +} + +variable "sqlserver_availability_no_data_timeframe" { + description = "SQL Server availability monitor no data timeframe" + type = string + default = 10 +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/sqlserver/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/sqlserver/modules.tf new file mode 100755 index 0000000..ad2d0d8 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/sqlserver/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "sqlserver" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/sqlserver/monitors-sqlserver.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/sqlserver/monitors-sqlserver.tf new file mode 100755 index 0000000..1e12d6c --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/sqlserver/monitors-sqlserver.tf @@ -0,0 +1,27 @@ +resource "datadog_monitor" "sqlserver_availability" { + count = var.sqlserver_availability_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] SQL Server server does not respond" + message = coalesce(var.sqlserver_availability_message, var.message) + type = "service check" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.datadog_monitor_zookeeper_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.not_responding](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before begin to monitor new host | `number` | `300` | no | +| [not\_responding\_group\_by](#input\_not\_responding\_group\_by) | List of tags to use to group data | `list(string)` |
[
"host",
"server"
]
| no | +| [not\_responding\_no\_data\_timeframe](#input\_not\_responding\_no\_data\_timeframe) | Zookeeper monitor no\_data\_timeframe | `number` | `10` | no | +| [not\_responding\_notify\_no\_data](#input\_not\_responding\_notify\_no\_data) | Send notification if not\_responding monitor does not retrieve data | `bool` | `true` | no | +| [not\_responding\_threshold\_warning](#input\_not\_responding\_threshold\_warning) | Zookeeper not responding limit (warning threshold) | `number` | `3` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [zookeeper\_latency\_availability\_extra\_tags](#input\_zookeeper\_latency\_availability\_extra\_tags) | Extra tags for zookeeper read latency monitor | `list(string)` | `[]` | no | +| [zookeeper\_latency\_enabled](#input\_zookeeper\_latency\_enabled) | Flag to enable Zookeeper read latency monitor | `string` | `"true"` | no | +| [zookeeper\_latency\_group\_by](#input\_zookeeper\_latency\_group\_by) | Tags to use to group datas | `list(string)` |
[
"host"
]
| no | +| [zookeeper\_latency\_status\_message](#input\_zookeeper\_latency\_status\_message) | Custom message for Zookeeper read latency monitor | `string` | `""` | no | +| [zookeeper\_latency\_threshold\_critical](#input\_zookeeper\_latency\_threshold\_critical) | Maximum critical acceptable ms of zookeeper latency monitor | `number` | `300000` | no | +| [zookeeper\_latency\_threshold\_warning](#input\_zookeeper\_latency\_threshold\_warning) | Maximum warning acceptable ms of zookeeper latency monitor | `number` | `250000` | no | +| [zookeeper\_latency\_time\_aggregator](#input\_zookeeper\_latency\_time\_aggregator) | Monitor time aggregator for Zookeeper read latency monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [zookeeper\_latency\_timeframe](#input\_zookeeper\_latency\_timeframe) | Monitor timeframe for Zookeeper read latency monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [zookeeper\_not\_responding\_enabled](#input\_zookeeper\_not\_responding\_enabled) | Flag to enable Zookeeper does not respond monitor | `string` | `"true"` | no | +| [zookeeper\_not\_responding\_extra\_tags](#input\_zookeeper\_not\_responding\_extra\_tags) | Extra tags for Zookeeper does not respond monitor | `list(string)` | `[]` | no | +| [zookeeper\_not\_responding\_message](#input\_zookeeper\_not\_responding\_message) | Custom message for Zookeeper does not respond monitor | `string` | `""` | no | +| [zookeeper\_not\_responding\_time\_aggregator](#input\_zookeeper\_not\_responding\_time\_aggregator) | Time aggregator for the Zookeeper does not respond monitor | `string` | `"avg"` | no | +| [zookeeper\_not\_responding\_timeframe](#input\_zookeeper\_not\_responding\_timeframe) | Timeframe for the does not respond monitor | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [datadog\_monitor\_zookeeper\_latency\_id](#output\_datadog\_monitor\_zookeeper\_latency\_id) | id for monitor datadog\_monitor\_zookeeper\_latency | +| [not\_responding\_id](#output\_not\_responding\_id) | id for monitor not\_responding | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/zk/](https://docs.datadoghq.com/integrations/zk/) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/zookeeper/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/zookeeper/inputs.tf new file mode 100755 index 0000000..3874747 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/zookeeper/inputs.tf @@ -0,0 +1,147 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before begin to monitor new host" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +# +# Service Check +# +variable "not_responding_notify_no_data" { + default = true + type = bool + description = "Send notification if not_responding monitor does not retrieve data" +} +variable "not_responding_no_data_timeframe" { + default = 10 + description = "Zookeeper monitor no_data_timeframe" + type = number +} + +variable "not_responding_group_by" { + default = ["host", "server"] + type = list(string) + description = "List of tags to use to group data" +} + +variable "zookeeper_not_responding_enabled" { + description = "Flag to enable Zookeeper does not respond monitor" + type = string + default = "true" +} + +variable "zookeeper_not_responding_message" { + description = "Custom message for Zookeeper does not respond monitor" + type = string + default = "" +} + +variable "zookeeper_not_responding_time_aggregator" { + description = "Time aggregator for the Zookeeper does not respond monitor" + type = string + default = "avg" +} + +variable "zookeeper_not_responding_timeframe" { + description = "Timeframe for the does not respond monitor" + type = string + default = "last_5m" +} + +variable "zookeeper_not_responding_extra_tags" { + description = "Extra tags for Zookeeper does not respond monitor" + type = list(string) + default = [] +} + +variable "not_responding_threshold_warning" { + default = 3 + type = number + description = "Zookeeper not responding limit (warning threshold)" +} + +# +# Check read latency monitor +# +variable "zookeeper_latency_enabled" { + description = "Flag to enable Zookeeper read latency monitor" + type = string + default = "true" +} + +variable "zookeeper_latency_group_by" { + description = "Tags to use to group datas" + type = list(string) + default = ["host"] +} + +variable "zookeeper_latency_status_message" { + description = "Custom message for Zookeeper read latency monitor" + type = string + default = "" +} + +variable "zookeeper_latency_time_aggregator" { + description = "Monitor time aggregator for Zookeeper read latency monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "zookeeper_latency_timeframe" { + description = "Monitor timeframe for Zookeeper read latency monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "zookeeper_latency_threshold_critical" { + description = "Maximum critical acceptable ms of zookeeper latency monitor" + default = 300000 +} + +variable "zookeeper_latency_threshold_warning" { + description = "Maximum warning acceptable ms of zookeeper latency monitor" + default = 250000 +} + +variable "zookeeper_latency_availability_extra_tags" { + description = "Extra tags for zookeeper read latency monitor" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/zookeeper/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/zookeeper/modules.tf new file mode 100755 index 0000000..f0cf5b4 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/zookeeper/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "zookeeper" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/zookeeper/monitors-zookeeper.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/zookeeper/monitors-zookeeper.tf new file mode 100755 index 0000000..3a32125 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/zookeeper/monitors-zookeeper.tf @@ -0,0 +1,57 @@ +resource "datadog_monitor" "not_responding" { + count = var.zookeeper_not_responding_enabled ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Zookeeper service does not respond {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.zookeeper_not_responding_message, var.message) + type = "service check" + + query = < ${var.zookeeper_latency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.zookeeper_latency_threshold_warning + critical = var.zookeeper_latency_threshold_critical + } + + notify_no_data = false + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:database", "provider:zookeeper", "resource:zookeeper", "team:claranet", "created-by:terraform"], var.zookeeper_latency_availability_extra_tags) + +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/zookeeper/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/zookeeper/outputs.tf new file mode 100755 index 0000000..f9403da --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/zookeeper/outputs.tf @@ -0,0 +1,10 @@ +output "datadog_monitor_zookeeper_latency_id" { + description = "id for monitor datadog_monitor_zookeeper_latency" + value = datadog_monitor.datadog_monitor_zookeeper_latency.*.id +} + +output "not_responding_id" { + description = "id for monitor not_responding" + value = datadog_monitor.not_responding.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/database/zookeeper/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/database/zookeeper/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/database/zookeeper/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/middleware/apache/README.md b/.terraform/modules/datadog-message-alerting-bh-only/middleware/apache/README.md new file mode 100755 index 0000000..af17369 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/middleware/apache/README.md @@ -0,0 +1,73 @@ +# MIDDLEWARE APACHE DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-middleware-apache" { + source = "claranet/monitors/datadog//middleware/apache" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Apache vhost status does not respond + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.datadog_apache_process](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [apache\_connect\_enabled](#input\_apache\_connect\_enabled) | Flag to enable Apache status monitor | `string` | `"true"` | no | +| [apache\_connect\_extra\_tags](#input\_apache\_connect\_extra\_tags) | Extra tags for Apache process monitor | `list(string)` | `[]` | no | +| [apache\_connect\_message](#input\_apache\_connect\_message) | Custom message for Apache status monitor | `string` | `""` | no | +| [apache\_connect\_threshold\_warning](#input\_apache\_connect\_threshold\_warning) | Apache status monitor (warning threshold) | `string` | `3` | no | +| [datadog\_apache\_process\_no\_data\_timeframe](#input\_datadog\_apache\_process\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [datadog\_apache\_process\_id](#output\_datadog\_apache\_process\_id) | id for monitor datadog\_apache\_process | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/apache/](https://docs.datadoghq.com/integrations/apache/) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/middleware/apache/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/middleware/apache/inputs.tf new file mode 100755 index 0000000..ed0cf18 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/middleware/apache/inputs.tf @@ -0,0 +1,78 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "datadog_apache_process_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Apache Middleware specific + +variable "apache_connect_enabled" { + description = "Flag to enable Apache status monitor" + type = string + default = "true" +} + +variable "apache_connect_extra_tags" { + description = "Extra tags for Apache process monitor" + type = list(string) + default = [] +} + +variable "apache_connect_message" { + description = "Custom message for Apache status monitor" + type = string + default = "" +} + +variable "apache_connect_threshold_warning" { + description = "Apache status monitor (warning threshold)" + type = string + default = 3 +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/middleware/apache/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/middleware/apache/modules.tf new file mode 100755 index 0000000..b84aa1b --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/middleware/apache/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "apache" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/middleware/apache/monitors-apache.tf b/.terraform/modules/datadog-message-alerting-bh-only/middleware/apache/monitors-apache.tf new file mode 100755 index 0000000..abe8811 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/middleware/apache/monitors-apache.tf @@ -0,0 +1,28 @@ +resource "datadog_monitor" "datadog_apache_process" { + count = var.apache_connect_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Apache vhost status does not respond" + message = coalesce(var.apache_connect_message, var.message) + type = "service check" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.not_responding](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.treatment_limit](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [not\_responding\_enabled](#input\_not\_responding\_enabled) | Flag to enable Kong does not respond monitor | `string` | `"true"` | no | +| [not\_responding\_extra\_tags](#input\_not\_responding\_extra\_tags) | Extra tags for Kong does not respond monitor | `list(string)` | `[]` | no | +| [not\_responding\_message](#input\_not\_responding\_message) | Custom message for Kong does not respond monitor | `string` | `""` | no | +| [not\_responding\_no\_data\_timeframe](#input\_not\_responding\_no\_data\_timeframe) | Kong does not respond monitor no data timeframe | `string` | `10` | no | +| [not\_responding\_threshold\_warning](#input\_not\_responding\_threshold\_warning) | Warning threshold for the service check | `string` | `3` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [treatment\_limit\_enabled](#input\_treatment\_limit\_enabled) | Flag to enable Kong Treatment Limit monitor | `string` | `"true"` | no | +| [treatment\_limit\_extra\_tags](#input\_treatment\_limit\_extra\_tags) | Extra tags for Kong Treatment Limit monitor | `list(string)` | `[]` | no | +| [treatment\_limit\_message](#input\_treatment\_limit\_message) | Custom message for the Kong Treatment Limit monitor | `string` | `""` | no | +| [treatment\_limit\_threshold\_critical](#input\_treatment\_limit\_threshold\_critical) | Docker Container Memory Usage critical threshold | `string` | `20` | no | +| [treatment\_limit\_threshold\_warning](#input\_treatment\_limit\_threshold\_warning) | Docker Container Memory Usage warning threshold | `string` | `0` | no | +| [treatment\_limit\_time\_aggregator](#input\_treatment\_limit\_time\_aggregator) | Time aggregator for the Kong Treatment Limit monitor | `string` | `"min"` | no | +| [treatment\_limit\_timeframe](#input\_treatment\_limit\_timeframe) | Timeframe for the Kong Treatment Limit monitor | `string` | `"last_15m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [not\_responding\_id](#output\_not\_responding\_id) | id for monitor not\_responding | +| [treatment\_limit\_id](#output\_treatment\_limit\_id) | id for monitor treatment\_limit | +## Related documentation + +* [Datadog Kong integration](https://docs.datadoghq.com/integrations/kong/) + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/middleware/kong/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/middleware/kong/inputs.tf new file mode 100755 index 0000000..06a3a02 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/middleware/kong/inputs.tf @@ -0,0 +1,126 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# +# Not Responding +# + +variable "not_responding_enabled" { + description = "Flag to enable Kong does not respond monitor" + type = string + default = "true" +} + +variable "not_responding_message" { + description = "Custom message for Kong does not respond monitor" + type = string + default = "" +} + +variable "not_responding_threshold_warning" { + description = "Warning threshold for the service check" + type = string + default = 3 +} + +variable "not_responding_no_data_timeframe" { + description = "Kong does not respond monitor no data timeframe" + type = string + default = 10 +} + +variable "not_responding_extra_tags" { + description = "Extra tags for Kong does not respond monitor" + type = list(string) + default = [] +} + +# +# Treatment Limit +# +variable "treatment_limit_enabled" { + description = "Flag to enable Kong Treatment Limit monitor" + type = string + default = "true" +} + +variable "treatment_limit_message" { + description = "Custom message for the Kong Treatment Limit monitor" + type = string + default = "" +} + +variable "treatment_limit_time_aggregator" { + description = "Time aggregator for the Kong Treatment Limit monitor" + type = string + default = "min" +} + +variable "treatment_limit_timeframe" { + description = "Timeframe for the Kong Treatment Limit monitor" + type = string + default = "last_15m" +} + +variable "treatment_limit_threshold_warning" { + description = "Docker Container Memory Usage warning threshold" + type = string + default = 0 +} + +variable "treatment_limit_threshold_critical" { + description = "Docker Container Memory Usage critical threshold" + type = string + default = 20 +} + +variable "treatment_limit_extra_tags" { + description = "Extra tags for Kong Treatment Limit monitor" + type = list(string) + default = [] +} + + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/middleware/kong/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/middleware/kong/modules.tf new file mode 100755 index 0000000..ff44bcb --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/middleware/kong/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "kong" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/middleware/kong/monitors-kong.tf b/.terraform/modules/datadog-message-alerting-bh-only/middleware/kong/monitors-kong.tf new file mode 100755 index 0000000..c2f9bc7 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/middleware/kong/monitors-kong.tf @@ -0,0 +1,62 @@ +# +# Service Check +# +resource "datadog_monitor" "not_responding" { + count = var.not_responding_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Kong does not respond" + message = coalesce(var.not_responding_message, var.message) + type = "service check" + + query = < ${var.treatment_limit_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.treatment_limit_threshold_warning + critical = var.treatment_limit_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:middleware", "provider:kong", "resource:kong", "team:claranet", "created-by:terraform"], var.treatment_limit_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/middleware/kong/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/middleware/kong/outputs.tf new file mode 100755 index 0000000..cbf2df8 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/middleware/kong/outputs.tf @@ -0,0 +1,10 @@ +output "not_responding_id" { + description = "id for monitor not_responding" + value = datadog_monitor.not_responding.*.id +} + +output "treatment_limit_id" { + description = "id for monitor treatment_limit" + value = datadog_monitor.treatment_limit.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/middleware/kong/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/middleware/kong/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/middleware/kong/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/middleware/nginx/README.md b/.terraform/modules/datadog-message-alerting-bh-only/middleware/nginx/README.md new file mode 100755 index 0000000..3591e85 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/middleware/nginx/README.md @@ -0,0 +1,82 @@ +# MIDDLEWARE NGINX DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-middleware-nginx" { + source = "claranet/monitors/datadog//middleware/nginx" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Nginx dropped connections +- Nginx vhost status does not respond + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.datadog_nginx_dropped_connections](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.datadog_nginx_process](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [nginx\_connect\_enabled](#input\_nginx\_connect\_enabled) | Flag to enable Nginx status monitor | `string` | `"true"` | no | +| [nginx\_connect\_extra\_tags](#input\_nginx\_connect\_extra\_tags) | Extra tags for Nginx process monitor | `list(string)` | `[]` | no | +| [nginx\_connect\_message](#input\_nginx\_connect\_message) | Custom message for Nginx status monitor | `string` | `""` | no | +| [nginx\_connect\_no\_data\_timeframe](#input\_nginx\_connect\_no\_data\_timeframe) | Nginx status monitor no data timeframe | `string` | `10` | no | +| [nginx\_connect\_threshold\_warning](#input\_nginx\_connect\_threshold\_warning) | Nginx status monitor (warning threshold) | `string` | `3` | no | +| [nginx\_dropped\_enabled](#input\_nginx\_dropped\_enabled) | Flag to enable Nginx dropped monitor | `string` | `"true"` | no | +| [nginx\_dropped\_extra\_tags](#input\_nginx\_dropped\_extra\_tags) | Extra tags for Nginx dropped connections monitor | `list(string)` | `[]` | no | +| [nginx\_dropped\_message](#input\_nginx\_dropped\_message) | Custom message for Nginx dropped connections monitor | `string` | `""` | no | +| [nginx\_dropped\_threshold\_critical](#input\_nginx\_dropped\_threshold\_critical) | Nginx dropped connections critical threshold | `number` | `0` | no | +| [nginx\_dropped\_time\_aggregator](#input\_nginx\_dropped\_time\_aggregator) | Monitor aggregator for Nginx dropped connections [available values: min, max or avg] | `string` | `"min"` | no | +| [nginx\_dropped\_timeframe](#input\_nginx\_dropped\_timeframe) | Monitor timeframe for Nginx dropped connections [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [datadog\_nginx\_dropped\_connections\_id](#output\_datadog\_nginx\_dropped\_connections\_id) | id for monitor datadog\_nginx\_dropped\_connections | +| [datadog\_nginx\_process\_id](#output\_datadog\_nginx\_process\_id) | id for monitor datadog\_nginx\_process | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/nginx/](https://docs.datadoghq.com/integrations/nginx/) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/middleware/nginx/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/middleware/nginx/inputs.tf new file mode 100755 index 0000000..9565887 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/middleware/nginx/inputs.tf @@ -0,0 +1,113 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Nginx Middleware specific + +variable "nginx_connect_enabled" { + description = "Flag to enable Nginx status monitor" + type = string + default = "true" +} + +variable "nginx_connect_extra_tags" { + description = "Extra tags for Nginx process monitor" + type = list(string) + default = [] +} + +variable "nginx_connect_message" { + description = "Custom message for Nginx status monitor" + type = string + default = "" +} + +variable "nginx_connect_threshold_warning" { + description = "Nginx status monitor (warning threshold)" + type = string + default = 3 +} + +variable "nginx_connect_no_data_timeframe" { + description = "Nginx status monitor no data timeframe" + type = string + default = 10 +} + +variable "nginx_dropped_enabled" { + description = "Flag to enable Nginx dropped monitor" + type = string + default = "true" +} + +variable "nginx_dropped_extra_tags" { + description = "Extra tags for Nginx dropped connections monitor" + type = list(string) + default = [] +} + +variable "nginx_dropped_message" { + description = "Custom message for Nginx dropped connections monitor" + type = string + default = "" +} + +variable "nginx_dropped_time_aggregator" { + description = "Monitor aggregator for Nginx dropped connections [available values: min, max or avg]" + type = string + default = "min" +} + +variable "nginx_dropped_timeframe" { + description = "Monitor timeframe for Nginx dropped connections [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "nginx_dropped_threshold_critical" { + description = "Nginx dropped connections critical threshold" + default = 0 +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/middleware/nginx/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/middleware/nginx/modules.tf new file mode 100755 index 0000000..3d2b17d --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/middleware/nginx/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "nginx" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/middleware/nginx/monitors-nginx.tf b/.terraform/modules/datadog-message-alerting-bh-only/middleware/nginx/monitors-nginx.tf new file mode 100755 index 0000000..e94ef15 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/middleware/nginx/monitors-nginx.tf @@ -0,0 +1,56 @@ +resource "datadog_monitor" "datadog_nginx_process" { + count = var.nginx_connect_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Nginx vhost status does not respond" + message = coalesce(var.nginx_connect_message, var.message) + type = "service check" + + query = < ${var.nginx_dropped_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.nginx_dropped_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:middleware", "provider:nginx", "resource:nginx", "team:claranet", "created-by:terraform"], var.nginx_dropped_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/middleware/nginx/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/middleware/nginx/outputs.tf new file mode 100755 index 0000000..60070fd --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/middleware/nginx/outputs.tf @@ -0,0 +1,10 @@ +output "datadog_nginx_dropped_connections_id" { + description = "id for monitor datadog_nginx_dropped_connections" + value = datadog_monitor.datadog_nginx_dropped_connections.*.id +} + +output "datadog_nginx_process_id" { + description = "id for monitor datadog_nginx_process" + value = datadog_monitor.datadog_nginx_process.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/middleware/nginx/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/middleware/nginx/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/middleware/nginx/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/middleware/php-fpm/README.md b/.terraform/modules/datadog-message-alerting-bh-only/middleware/php-fpm/README.md new file mode 100755 index 0000000..b191831 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/middleware/php-fpm/README.md @@ -0,0 +1,83 @@ +# MIDDLEWARE PHP-FPM DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-middleware-php-fpm" { + source = "claranet/monitors/datadog//middleware/php-fpm" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Php-fpm busy worker +- Php-fpm ping url does not respond + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.php_fpm_connect](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.php_fpm_connect_idle](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [php\_fpm\_busy\_enabled](#input\_php\_fpm\_busy\_enabled) | Flag to enable PHP FPM busy worker monitor | `string` | `"true"` | no | +| [php\_fpm\_busy\_extra\_tags](#input\_php\_fpm\_busy\_extra\_tags) | Extra tags for PHP FPM busy worker monitor | `list(string)` | `[]` | no | +| [php\_fpm\_busy\_message](#input\_php\_fpm\_busy\_message) | Custom message for PHP FPM busy worker monitor | `string` | `""` | no | +| [php\_fpm\_busy\_threshold\_critical](#input\_php\_fpm\_busy\_threshold\_critical) | php fpm busy critical threshold | `number` | `90` | no | +| [php\_fpm\_busy\_threshold\_warning](#input\_php\_fpm\_busy\_threshold\_warning) | php fpm busy warning threshold | `number` | `80` | no | +| [php\_fpm\_busy\_time\_aggregator](#input\_php\_fpm\_busy\_time\_aggregator) | Monitor aggregator for PHP FPM busy worker [available values: min, max or avg] | `string` | `"avg"` | no | +| [php\_fpm\_busy\_timeframe](#input\_php\_fpm\_busy\_timeframe) | Monitor timeframe for PHP FPM busy worker [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_10m"` | no | +| [php\_fpm\_connect\_enabled](#input\_php\_fpm\_connect\_enabled) | Flag to enable PHP FPM status monitor | `string` | `"true"` | no | +| [php\_fpm\_connect\_extra\_tags](#input\_php\_fpm\_connect\_extra\_tags) | Extra tags for PHP FPM status monitor | `list(string)` | `[]` | no | +| [php\_fpm\_connect\_message](#input\_php\_fpm\_connect\_message) | Custom message for PHP FPM status monitor | `string` | `""` | no | +| [php\_fpm\_connect\_no\_data\_timeframe](#input\_php\_fpm\_connect\_no\_data\_timeframe) | PHP FPM status monitor no data timeframe | `string` | `10` | no | +| [php\_fpm\_connect\_threshold\_warning](#input\_php\_fpm\_connect\_threshold\_warning) | PHP FPM status monitor (warning threshold) | `string` | `3` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [php\_fpm\_connect\_id](#output\_php\_fpm\_connect\_id) | id for monitor php\_fpm\_connect | +| [php\_fpm\_connect\_idle\_id](#output\_php\_fpm\_connect\_idle\_id) | id for monitor php\_fpm\_connect\_idle | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/php_fpm/](https://docs.datadoghq.com/integrations/php_fpm/) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/middleware/php-fpm/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/middleware/php-fpm/inputs.tf new file mode 100755 index 0000000..a4e05bb --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/middleware/php-fpm/inputs.tf @@ -0,0 +1,118 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# PHP FPM Middleware specific + +variable "php_fpm_busy_enabled" { + description = "Flag to enable PHP FPM busy worker monitor" + type = string + default = "true" +} + +variable "php_fpm_busy_extra_tags" { + description = "Extra tags for PHP FPM busy worker monitor" + type = list(string) + default = [] +} + +variable "php_fpm_busy_message" { + description = "Custom message for PHP FPM busy worker monitor" + type = string + default = "" +} + +variable "php_fpm_busy_time_aggregator" { + description = "Monitor aggregator for PHP FPM busy worker [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "php_fpm_busy_timeframe" { + description = "Monitor timeframe for PHP FPM busy worker [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_10m" +} + +variable "php_fpm_busy_threshold_warning" { + description = "php fpm busy warning threshold" + default = 80 +} + +variable "php_fpm_busy_threshold_critical" { + description = "php fpm busy critical threshold" + default = 90 +} + +variable "php_fpm_connect_enabled" { + description = "Flag to enable PHP FPM status monitor" + type = string + default = "true" +} + +variable "php_fpm_connect_extra_tags" { + description = "Extra tags for PHP FPM status monitor" + type = list(string) + default = [] +} + +variable "php_fpm_connect_message" { + description = "Custom message for PHP FPM status monitor" + type = string + default = "" +} + +variable "php_fpm_connect_threshold_warning" { + description = "PHP FPM status monitor (warning threshold)" + type = string + default = 3 +} + +variable "php_fpm_connect_no_data_timeframe" { + description = "PHP FPM status monitor no data timeframe" + type = string + default = 10 +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/middleware/php-fpm/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/middleware/php-fpm/modules.tf new file mode 100755 index 0000000..9d90639 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/middleware/php-fpm/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "php-fpm" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/middleware/php-fpm/monitors-fpm.tf b/.terraform/modules/datadog-message-alerting-bh-only/middleware/php-fpm/monitors-fpm.tf new file mode 100755 index 0000000..3ef7883 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/middleware/php-fpm/monitors-fpm.tf @@ -0,0 +1,59 @@ +resource "datadog_monitor" "php_fpm_connect" { + count = var.php_fpm_connect_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Php-fpm ping url does not respond" + message = coalesce(var.php_fpm_connect_message, var.message) + type = "service check" + + query = < ${var.php_fpm_busy_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.php_fpm_busy_threshold_warning + critical = var.php_fpm_busy_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:middleware", "provider:php-fpm", "resource:php-fpm", "team:claranet", "created-by:terraform"], var.php_fpm_busy_extra_tags) +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/middleware/php-fpm/outputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/middleware/php-fpm/outputs.tf new file mode 100755 index 0000000..1d7408a --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/middleware/php-fpm/outputs.tf @@ -0,0 +1,10 @@ +output "php_fpm_connect_id" { + description = "id for monitor php_fpm_connect" + value = datadog_monitor.php_fpm_connect.*.id +} + +output "php_fpm_connect_idle_id" { + description = "id for monitor php_fpm_connect_idle" + value = datadog_monitor.php_fpm_connect_idle.*.id +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/middleware/php-fpm/versions.tf b/.terraform/modules/datadog-message-alerting-bh-only/middleware/php-fpm/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/middleware/php-fpm/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/network/dns/README.md b/.terraform/modules/datadog-message-alerting-bh-only/network/dns/README.md new file mode 100755 index 0000000..4e0e5b6 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/network/dns/README.md @@ -0,0 +1,73 @@ +# NETWORK DNS DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-network-dns" { + source = "claranet/monitors/datadog//network/dns" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- DNS cannot resolve + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cannot_resolve](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cannot\_resolve\_enabled](#input\_cannot\_resolve\_enabled) | Flag to enable DNS cannot resolve monitor | `string` | `"true"` | no | +| [cannot\_resolve\_extra\_tags](#input\_cannot\_resolve\_extra\_tags) | Extra tags for DNS cannot resolve monitor | `list(string)` | `[]` | no | +| [cannot\_resolve\_message](#input\_cannot\_resolve\_message) | Custom message for DNS cannot resolve monitor | `string` | `""` | no | +| [cannot\_resolve\_no\_data\_timeframe](#input\_cannot\_resolve\_no\_data\_timeframe) | DNS cannot resolve monitor no data timeframe | `string` | `10` | no | +| [cannot\_resolve\_threshold\_warning](#input\_cannot\_resolve\_threshold\_warning) | DNS cannot resolve monitor (warning threshold) | `string` | `3` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cannot\_resolve\_id](#output\_cannot\_resolve\_id) | id for monitor cannot\_resolve | +## Related documentation + +- [Datadog DNS integration](https://docs.datadoghq.com/integrations/dns_check/) diff --git a/.terraform/modules/datadog-message-alerting-bh-only/network/dns/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/network/dns/inputs.tf new file mode 100755 index 0000000..c00e0f3 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/network/dns/inputs.tf @@ -0,0 +1,78 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# +# Cannot Resolve +# +variable "cannot_resolve_enabled" { + description = "Flag to enable DNS cannot resolve monitor" + type = string + default = "true" +} + +variable "cannot_resolve_message" { + description = "Custom message for DNS cannot resolve monitor" + type = string + default = "" +} + +variable "cannot_resolve_threshold_warning" { + description = "DNS cannot resolve monitor (warning threshold)" + type = string + default = 3 +} + +variable "cannot_resolve_no_data_timeframe" { + description = "DNS cannot resolve monitor no data timeframe" + type = string + default = 10 +} + +variable "cannot_resolve_extra_tags" { + description = "Extra tags for DNS cannot resolve monitor" + type = list(string) + default = [] +} \ No newline at end of file diff --git a/.terraform/modules/datadog-message-alerting-bh-only/network/dns/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/network/dns/modules.tf new file mode 100755 index 0000000..03747be --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/network/dns/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "dns" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/network/dns/monitors-dns.tf b/.terraform/modules/datadog-message-alerting-bh-only/network/dns/monitors-dns.tf new file mode 100755 index 0000000..187ce96 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/network/dns/monitors-dns.tf @@ -0,0 +1,30 @@ +# +# Service Check +# +resource "datadog_monitor" "cannot_resolve" { + count = var.cannot_resolve_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] DNS cannot resolve" + message = coalesce(var.cannot_resolve_message, var.message) + type = "service check" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.certificate_expiration_date](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.invalid_ssl_certificate](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [certificate\_expiration\_date\_enabled](#input\_certificate\_expiration\_date\_enabled) | Flag to enable Certificate Expiration Date monitor | `string` | `"false"` | no | +| [certificate\_expiration\_date\_extra\_tags](#input\_certificate\_expiration\_date\_extra\_tags) | Extra tags for Certificate Expiration Date monitor | `list(string)` | `[]` | no | +| [certificate\_expiration\_date\_message](#input\_certificate\_expiration\_date\_message) | Custom message for the Certificate Expiration Date monitor | `string` | `""` | no | +| [certificate\_expiration\_date\_threshold\_critical](#input\_certificate\_expiration\_date\_threshold\_critical) | Certificate Expiration Date critical threshold | `string` | `15` | no | +| [certificate\_expiration\_date\_threshold\_warning](#input\_certificate\_expiration\_date\_threshold\_warning) | Certificate Expiration Date warning threshold | `string` | `30` | no | +| [certificate\_expiration\_date\_time\_aggregator](#input\_certificate\_expiration\_date\_time\_aggregator) | Time aggregator for the Certificate Expiration Date monitor | `string` | `"max"` | no | +| [certificate\_expiration\_date\_timeframe](#input\_certificate\_expiration\_date\_timeframe) | Timeframe for the Certificate Expiration Date monitor | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [invalid\_ssl\_certificate\_enabled](#input\_invalid\_ssl\_certificate\_enabled) | Flag to enable SSL invalid certificate monitor | `string` | `"true"` | no | +| [invalid\_ssl\_certificate\_extra\_tags](#input\_invalid\_ssl\_certificate\_extra\_tags) | Extra tags for SSL invalid certificate monitor | `list(string)` | `[]` | no | +| [invalid\_ssl\_certificate\_message](#input\_invalid\_ssl\_certificate\_message) | Custom message for SSL invalid certificate monitor | `string` | `""` | no | +| [invalid\_ssl\_certificate\_no\_data\_timeframe](#input\_invalid\_ssl\_certificate\_no\_data\_timeframe) | SSL invalid certificate monitor no data timeframe | `string` | `10` | no | +| [invalid\_ssl\_certificate\_threshold\_warning](#input\_invalid\_ssl\_certificate\_threshold\_warning) | SSL invalid certificate monitor (warning threshold) | `string` | `3` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [certificate\_expiration\_date\_id](#output\_certificate\_expiration\_date\_id) | id for monitor certificate\_expiration\_date | +| [invalid\_ssl\_certificate\_id](#output\_invalid\_ssl\_certificate\_id) | id for monitor invalid\_ssl\_certificate | +## Related documentation + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/network/http/ssl/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/network/http/ssl/inputs.tf new file mode 100755 index 0000000..5ce2426 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/network/http/ssl/inputs.tf @@ -0,0 +1,123 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# +# SSL invalid certificate +# +variable "invalid_ssl_certificate_enabled" { + description = "Flag to enable SSL invalid certificate monitor" + type = string + default = "true" +} + +variable "invalid_ssl_certificate_message" { + description = "Custom message for SSL invalid certificate monitor" + type = string + default = "" +} + +variable "invalid_ssl_certificate_threshold_warning" { + description = "SSL invalid certificate monitor (warning threshold)" + type = string + default = 3 +} + +variable "invalid_ssl_certificate_no_data_timeframe" { + description = "SSL invalid certificate monitor no data timeframe" + type = string + default = 10 +} + +variable "invalid_ssl_certificate_extra_tags" { + description = "Extra tags for SSL invalid certificate monitor" + type = list(string) + default = [] +} + +# +# Certificate Expiration Date +# +variable "certificate_expiration_date_enabled" { + description = "Flag to enable Certificate Expiration Date monitor" + type = string + default = "false" +} + +variable "certificate_expiration_date_message" { + description = "Custom message for the Certificate Expiration Date monitor" + type = string + default = "" +} + +variable "certificate_expiration_date_time_aggregator" { + description = "Time aggregator for the Certificate Expiration Date monitor" + type = string + default = "max" +} + +variable "certificate_expiration_date_timeframe" { + description = "Timeframe for the Certificate Expiration Date monitor" + type = string + default = "last_5m" +} + +variable "certificate_expiration_date_threshold_warning" { + description = "Certificate Expiration Date warning threshold" + type = string + default = 30 +} + +variable "certificate_expiration_date_threshold_critical" { + description = "Certificate Expiration Date critical threshold" + type = string + default = 15 +} + +variable "certificate_expiration_date_extra_tags" { + description = "Extra tags for Certificate Expiration Date monitor" + type = list(string) + default = [] +} \ No newline at end of file diff --git a/.terraform/modules/datadog-message-alerting-bh-only/network/http/ssl/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/network/http/ssl/modules.tf new file mode 100755 index 0000000..1a8b9bf --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/network/http/ssl/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "http" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/network/http/ssl/monitors-ssl.tf b/.terraform/modules/datadog-message-alerting-bh-only/network/http/ssl/monitors-ssl.tf new file mode 100755 index 0000000..78d65c0 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/network/http/ssl/monitors-ssl.tf @@ -0,0 +1,63 @@ +# +# Invalid SSL Certificate +# +resource "datadog_monitor" "invalid_ssl_certificate" { + count = var.invalid_ssl_certificate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] SSL invalid certificate" + message = coalesce(var.invalid_ssl_certificate_message, var.message) + type = "service check" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cannot_connect](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cannot\_connect\_enabled](#input\_cannot\_connect\_enabled) | Flag to enable HTTP cannot connect monitor | `string` | `"true"` | no | +| [cannot\_connect\_extra\_tags](#input\_cannot\_connect\_extra\_tags) | Extra tags for HTTP cannot connect monitor | `list(string)` | `[]` | no | +| [cannot\_connect\_message](#input\_cannot\_connect\_message) | Custom message for HTTP cannot connect monitor | `string` | `""` | no | +| [cannot\_connect\_no\_data\_timeframe](#input\_cannot\_connect\_no\_data\_timeframe) | HTTP cannot connect monitor no data timeframe | `string` | `10` | no | +| [cannot\_connect\_threshold\_warning](#input\_cannot\_connect\_threshold\_warning) | HTTP cannot connect monitor (warning threshold) | `string` | `3` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cannot\_connect\_id](#output\_cannot\_connect\_id) | id for monitor cannot\_connect | +## Related documentation + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/network/http/webcheck/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/network/http/webcheck/inputs.tf new file mode 100755 index 0000000..ad7564b --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/network/http/webcheck/inputs.tf @@ -0,0 +1,78 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# +# HTTP Cannot Connect +# +variable "cannot_connect_enabled" { + description = "Flag to enable HTTP cannot connect monitor" + type = string + default = "true" +} + +variable "cannot_connect_message" { + description = "Custom message for HTTP cannot connect monitor" + type = string + default = "" +} + +variable "cannot_connect_threshold_warning" { + description = "HTTP cannot connect monitor (warning threshold)" + type = string + default = 3 +} + +variable "cannot_connect_no_data_timeframe" { + description = "HTTP cannot connect monitor no data timeframe" + type = string + default = 10 +} + +variable "cannot_connect_extra_tags" { + description = "Extra tags for HTTP cannot connect monitor" + type = list(string) + default = [] +} \ No newline at end of file diff --git a/.terraform/modules/datadog-message-alerting-bh-only/network/http/webcheck/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/network/http/webcheck/modules.tf new file mode 100755 index 0000000..1a8b9bf --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/network/http/webcheck/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "http" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/network/http/webcheck/monitors-webcheck.tf b/.terraform/modules/datadog-message-alerting-bh-only/network/http/webcheck/monitors-webcheck.tf new file mode 100755 index 0000000..fc785c9 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/network/http/webcheck/monitors-webcheck.tf @@ -0,0 +1,30 @@ +# +# HTTP Cannot Connect +# +resource "datadog_monitor" "cannot_connect" { + count = var.cannot_connect_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] HTTP cannot connect" + message = coalesce(var.cannot_connect_message, var.message) + type = "service check" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cannot_connect](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.certificate_expiration_date](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.invalid_tls_certificate](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.tls_certificate_expiration](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cannot\_connect\_enabled](#input\_cannot\_connect\_enabled) | Flag to enable TLS cannot connect monitor | `string` | `"true"` | no | +| [cannot\_connect\_extra\_tags](#input\_cannot\_connect\_extra\_tags) | Extra tags for TLS cannot connect monitor | `list(string)` | `[]` | no | +| [cannot\_connect\_message](#input\_cannot\_connect\_message) | Custom message for TLS cannot connect monitor | `string` | `""` | no | +| [cannot\_connect\_no\_data\_timeframe](#input\_cannot\_connect\_no\_data\_timeframe) | TLS cannot connect monitor no data timeframe | `string` | `10` | no | +| [cannot\_connect\_threshold\_warning](#input\_cannot\_connect\_threshold\_warning) | TLS cannot connect monitor (warning threshold) | `string` | `3` | no | +| [certificate\_expiration\_date\_enabled](#input\_certificate\_expiration\_date\_enabled) | Flag to enable Certificate Expiration Date monitor | `string` | `"false"` | no | +| [certificate\_expiration\_date\_extra\_tags](#input\_certificate\_expiration\_date\_extra\_tags) | Extra tags for Certificate Expiration Date monitor | `list(string)` | `[]` | no | +| [certificate\_expiration\_date\_message](#input\_certificate\_expiration\_date\_message) | Custom message for the Certificate Expiration Date monitor | `string` | `""` | no | +| [certificate\_expiration\_date\_threshold\_critical](#input\_certificate\_expiration\_date\_threshold\_critical) | Container Memory Usage critical threshold | `string` | `15` | no | +| [certificate\_expiration\_date\_threshold\_warning](#input\_certificate\_expiration\_date\_threshold\_warning) | Container Memory Usage warning threshold | `string` | `30` | no | +| [certificate\_expiration\_date\_time\_aggregator](#input\_certificate\_expiration\_date\_time\_aggregator) | Time aggregator for the Certificate Expiration Date monitor | `string` | `"max"` | no | +| [certificate\_expiration\_date\_timeframe](#input\_certificate\_expiration\_date\_timeframe) | Timeframe for the Certificate Expiration Date monitor | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [invalid\_tls\_certificate\_enabled](#input\_invalid\_tls\_certificate\_enabled) | Flag to enable TLS certificate expiration monitor | `string` | `"true"` | no | +| [invalid\_tls\_certificate\_extra\_tags](#input\_invalid\_tls\_certificate\_extra\_tags) | Extra tags for TLS certificate expiration monitor | `list(string)` | `[]` | no | +| [invalid\_tls\_certificate\_message](#input\_invalid\_tls\_certificate\_message) | Custom message for TLS certificate expiration monitor | `string` | `""` | no | +| [invalid\_tls\_certificate\_threshold\_warning](#input\_invalid\_tls\_certificate\_threshold\_warning) | TLS certificate expiration monitor (warning threshold) | `string` | `3` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [tls\_certificate\_expiration\_enabled](#input\_tls\_certificate\_expiration\_enabled) | Flag to enable TLS certificate expiration monitor | `string` | `"true"` | no | +| [tls\_certificate\_expiration\_extra\_tags](#input\_tls\_certificate\_expiration\_extra\_tags) | Extra tags for TLS certificate expiration monitor | `list(string)` | `[]` | no | +| [tls\_certificate\_expiration\_message](#input\_tls\_certificate\_expiration\_message) | Custom message for TLS certificate expiration monitor | `string` | `""` | no | +| [tls\_certificate\_expiration\_threshold\_warning](#input\_tls\_certificate\_expiration\_threshold\_warning) | TLS certificate expiration monitor (warning threshold) | `string` | `5` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cannot\_connect\_id](#output\_cannot\_connect\_id) | id for monitor cannot\_connect | +| [certificate\_expiration\_date\_id](#output\_certificate\_expiration\_date\_id) | id for monitor certificate\_expiration\_date | +| [invalid\_tls\_certificate\_id](#output\_invalid\_tls\_certificate\_id) | id for monitor invalid\_tls\_certificate | +| [tls\_certificate\_expiration\_id](#output\_tls\_certificate\_expiration\_id) | id for monitor tls\_certificate\_expiration | +## Related documentation + +- [Datadog TLS integration](https://docs.datadoghq.com/integrations/tls/) + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/network/tls/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/network/tls/inputs.tf new file mode 100755 index 0000000..cb0ecde --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/network/tls/inputs.tf @@ -0,0 +1,177 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# +# TLS Cannot Connect +# +variable "cannot_connect_enabled" { + description = "Flag to enable TLS cannot connect monitor" + type = string + default = "true" +} + +variable "cannot_connect_message" { + description = "Custom message for TLS cannot connect monitor" + type = string + default = "" +} + +variable "cannot_connect_threshold_warning" { + description = "TLS cannot connect monitor (warning threshold)" + type = string + default = 3 +} + +variable "cannot_connect_no_data_timeframe" { + description = "TLS cannot connect monitor no data timeframe" + type = string + default = 10 +} + +variable "cannot_connect_extra_tags" { + description = "Extra tags for TLS cannot connect monitor" + type = list(string) + default = [] +} + +# +# TLS invalid certificate +# +variable "invalid_tls_certificate_enabled" { + description = "Flag to enable TLS certificate expiration monitor" + type = string + default = "true" +} + +variable "invalid_tls_certificate_message" { + description = "Custom message for TLS certificate expiration monitor" + type = string + default = "" +} + +variable "invalid_tls_certificate_threshold_warning" { + description = "TLS certificate expiration monitor (warning threshold)" + type = string + default = 3 +} + +variable "invalid_tls_certificate_extra_tags" { + description = "Extra tags for TLS certificate expiration monitor" + type = list(string) + default = [] +} + +# +# TLS Certificate Expiration +# +variable "tls_certificate_expiration_enabled" { + description = "Flag to enable TLS certificate expiration monitor" + type = string + default = "true" +} + +variable "tls_certificate_expiration_message" { + description = "Custom message for TLS certificate expiration monitor" + type = string + default = "" +} + +variable "tls_certificate_expiration_threshold_warning" { + description = "TLS certificate expiration monitor (warning threshold)" + type = string + default = 5 +} + +variable "tls_certificate_expiration_extra_tags" { + description = "Extra tags for TLS certificate expiration monitor" + type = list(string) + default = [] +} + +# +# Certificate Expiration Date +# +variable "certificate_expiration_date_enabled" { + description = "Flag to enable Certificate Expiration Date monitor" + type = string + default = "false" +} + +variable "certificate_expiration_date_message" { + description = "Custom message for the Certificate Expiration Date monitor" + type = string + default = "" +} + +variable "certificate_expiration_date_time_aggregator" { + description = "Time aggregator for the Certificate Expiration Date monitor" + type = string + default = "max" +} + +variable "certificate_expiration_date_timeframe" { + description = "Timeframe for the Certificate Expiration Date monitor" + type = string + default = "last_5m" +} + +variable "certificate_expiration_date_threshold_warning" { + description = "Container Memory Usage warning threshold" + type = string + default = 30 +} + +variable "certificate_expiration_date_threshold_critical" { + description = "Container Memory Usage critical threshold" + type = string + default = 15 +} + +variable "certificate_expiration_date_extra_tags" { + description = "Extra tags for Certificate Expiration Date monitor" + type = list(string) + default = [] +} \ No newline at end of file diff --git a/.terraform/modules/datadog-message-alerting-bh-only/network/tls/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/network/tls/modules.tf new file mode 100755 index 0000000..941bec4 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/network/tls/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "tls" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/network/tls/monitors-tls.tf b/.terraform/modules/datadog-message-alerting-bh-only/network/tls/monitors-tls.tf new file mode 100755 index 0000000..35df142 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/network/tls/monitors-tls.tf @@ -0,0 +1,124 @@ +# +# TLS Cannot Connect +# +resource "datadog_monitor" "cannot_connect" { + count = var.cannot_connect_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] TLS cannot connect" + message = coalesce(var.cannot_connect_message, var.message) + type = "service check" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.app_apdex_score](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.app_error_rate](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [app\_apdex\_score\_enabled](#input\_app\_apdex\_score\_enabled) | Flag to enable APP Apdex Score monitor | `string` | `"true"` | no | +| [app\_apdex\_score\_extra\_tags](#input\_app\_apdex\_score\_extra\_tags) | Extra tags for New Relic APP Apdex Score monitor | `list(string)` | `[]` | no | +| [app\_apdex\_score\_message](#input\_app\_apdex\_score\_message) | Custom message for the APP Apdex Score monitor | `string` | `""` | no | +| [app\_apdex\_score\_threshold\_critical](#input\_app\_apdex\_score\_threshold\_critical) | APP Apdex Score critical threshold | `string` | `0.25` | no | +| [app\_apdex\_score\_threshold\_warning](#input\_app\_apdex\_score\_threshold\_warning) | APP Apdex Score warning threshold | `string` | `0.5` | no | +| [app\_apdex\_score\_time\_aggregator](#input\_app\_apdex\_score\_time\_aggregator) | Time aggregator for the APP Apdex Score monitor | `string` | `"avg"` | no | +| [app\_apdex\_score\_timeframe](#input\_app\_apdex\_score\_timeframe) | Timeframe for the APP Apdex Score monitor | `string` | `"last_15m"` | no | +| [app\_error\_rate\_enabled](#input\_app\_error\_rate\_enabled) | Flag to enable APP Error Rate monitor | `string` | `"true"` | no | +| [app\_error\_rate\_extra\_tags](#input\_app\_error\_rate\_extra\_tags) | Extra tags for New Relic APP Error Rate monitor | `list(string)` | `[]` | no | +| [app\_error\_rate\_message](#input\_app\_error\_rate\_message) | Custom message for the APP Error Rate monitor | `string` | `""` | no | +| [app\_error\_rate\_threshold\_critical](#input\_app\_error\_rate\_threshold\_critical) | APP Error Rate critical threshold | `string` | `5` | no | +| [app\_error\_rate\_threshold\_warning](#input\_app\_error\_rate\_threshold\_warning) | APP Error Rate warning threshold | `string` | `1` | no | +| [app\_error\_rate\_time\_aggregator](#input\_app\_error\_rate\_time\_aggregator) | Time aggregator for the APP Error Rate monitor | `string` | `"min"` | no | +| [app\_error\_rate\_timeframe](#input\_app\_error\_rate\_timeframe) | Timeframe for the APP Error Rate monitor | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [app\_apdex\_score\_id](#output\_app\_apdex\_score\_id) | id for monitor app\_apdex\_score | +| [app\_error\_rate\_id](#output\_app\_error\_rate\_id) | id for monitor app\_error\_rate | +## Related documentation + +* [Datadog New Relic integration](https://docs.datadoghq.com/integrations/new_relic/) + + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/saas/new-relic/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/saas/new-relic/inputs.tf new file mode 100755 index 0000000..473a4eb --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/saas/new-relic/inputs.tf @@ -0,0 +1,135 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# +# APP Error Rate +# +variable "app_error_rate_enabled" { + description = "Flag to enable APP Error Rate monitor" + type = string + default = "true" +} + +variable "app_error_rate_message" { + description = "Custom message for the APP Error Rate monitor" + type = string + default = "" +} + +variable "app_error_rate_time_aggregator" { + description = "Time aggregator for the APP Error Rate monitor" + type = string + default = "min" +} + +variable "app_error_rate_timeframe" { + description = "Timeframe for the APP Error Rate monitor" + type = string + default = "last_5m" +} + +variable "app_error_rate_threshold_warning" { + description = "APP Error Rate warning threshold" + type = string + default = 1 +} + +variable "app_error_rate_threshold_critical" { + description = "APP Error Rate critical threshold" + type = string + default = 5 +} + +variable "app_error_rate_extra_tags" { + description = "Extra tags for New Relic APP Error Rate monitor" + type = list(string) + default = [] +} + +# +# APP Apdex Score +# +variable "app_apdex_score_enabled" { + description = "Flag to enable APP Apdex Score monitor" + type = string + default = "true" +} + +variable "app_apdex_score_message" { + description = "Custom message for the APP Apdex Score monitor" + type = string + default = "" +} + +variable "app_apdex_score_time_aggregator" { + description = "Time aggregator for the APP Apdex Score monitor" + type = string + default = "avg" +} + +variable "app_apdex_score_timeframe" { + description = "Timeframe for the APP Apdex Score monitor" + type = string + default = "last_15m" +} + +variable "app_apdex_score_threshold_warning" { + description = "APP Apdex Score warning threshold" + type = string + default = 0.5 +} + +variable "app_apdex_score_threshold_critical" { + description = "APP Apdex Score critical threshold" + type = string + default = 0.25 +} + +variable "app_apdex_score_extra_tags" { + description = "Extra tags for New Relic APP Apdex Score monitor" + type = list(string) + default = [] +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/saas/new-relic/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/saas/new-relic/modules.tf new file mode 100755 index 0000000..7e6a157 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/saas/new-relic/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "new_relic" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} diff --git a/.terraform/modules/datadog-message-alerting-bh-only/saas/new-relic/monitors-new-relic.tf b/.terraform/modules/datadog-message-alerting-bh-only/saas/new-relic/monitors-new-relic.tf new file mode 100755 index 0000000..05080aa --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/saas/new-relic/monitors-new-relic.tf @@ -0,0 +1,59 @@ +resource "datadog_monitor" "app_error_rate" { + count = var.app_error_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] New Relic Error rate {{#is_alert}}{{{comparator}}} {{threshold}}errs/min ({{value}}errs/min){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}errs/min ({{value}}errs/min){{/is_warning}}" + message = coalesce(var.app_error_rate_message, var.message) + type = "query alert" + + query = < ${var.app_error_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.app_error_rate_threshold_warning + critical = var.app_error_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:saas", "provider:new-relic", "resource:new-relic", "team:claranet", "created-by:terraform"], var.app_error_rate_extra_tags) +} + +resource "datadog_monitor" "app_apdex_score" { + count = var.app_apdex_score_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] New Relic Apdex score ratio {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.app_apdex_score_message, var.message) + type = "query alert" + + query = < /dev/null 2>&1; then + echo "This requires ${cmd} command, please install it first." + exit 1 + fi +} + +function verlte() { + [ "$1" = "$(echo -e "$1\n$2" | sort -V | head -n1)" ] +} + +function verlt() { + [ "$1" = "$2" ] && return 1 || verlte $1 $2 +} + +function check_version() { + if [[ "$1" == "terraform" ]]; then + tmp_dir=$(mktemp -d) + cd ${tmp_dir} + set +o pipefail # terraform fails on command piping when not last version + cur_ver=$(terraform version | head -n 1 | cut -d' ' -f2) + set -o pipefail + cur_ver=${cur_ver#"v"} + cd - > /dev/null + rm -fr ${tmp_dir} + req_ver=$(grep required_version README.md | awk '{print $4}') + req_ver=${req_ver%'"'} + elif [[ "$1" == "terraform-docs" ]]; then + if [[ "$(grep terraform-docs README.md)" =~ [[:space:]]v([0-9]*\.[0-9]*\.[0-9]*).*\. ]]; then + req_ver="${BASH_REMATCH[1]}" + else + echo "impossible to retrieve required terraform-docs version from README" + exit 3 + fi + cur_ver=$(terraform-docs --version) + else + return 0 + fi + if ! verlte $req_ver $cur_ver; then + echo "This requires at least version ${req_ver} of $1, please upgrade (current version is ${cur_ver})" + exit 2 + fi +} + +for cmd in terraform terraform-docs terraform-config-inspect jq; do + echo -e "\t- Check command \"$cmd\" exists and in right version" + check_command $cmd + check_version $cmd +done diff --git a/.terraform/modules/datadog-message-alerting-bh-only/scripts/10_update_output.sh b/.terraform/modules/datadog-message-alerting-bh-only/scripts/10_update_output.sh new file mode 100755 index 0000000..2a55c24 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/scripts/10_update_output.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +source "$(dirname $0)/utils.sh" +init +if [ "${REPO}" != "monitors" ]; then + # Run this script only for monitors repo + exit 0 +fi +echo "Generate terraform outputs.tf files for every monitors modules" + +# loop over every modules +for module in $(browse_modules "$(get_scope ${1:-})" "${REPO}-*.tf"); do + echo -e "\t- Generate outputs.tf for module: ${module}" + cd ${module} + # empty outputs + > outputs.tf + # gather a information line splitted with "|" for every monitor + for row in $(terraform-config-inspect --json | jq -c -r '.managed_resources | map([.name] | join("|")) | join("\n")'); do + # split line for each info one variable + IFS='|' read monitor type < <(echo $row) + # create output block for current monitor + cat >> outputs.tf <> /dev/null +done diff --git a/.terraform/modules/datadog-message-alerting-bh-only/scripts/20_update_global_readme.sh b/.terraform/modules/datadog-message-alerting-bh-only/scripts/20_update_global_readme.sh new file mode 100755 index 0000000..3f7e538 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/scripts/20_update_global_readme.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +source "$(dirname $0)/utils.sh" +init +echo "Update global README.md" + +# only keep current README from begining to "[Monitors/Integrations] summary" section (delete list) +sed -i "/## ${REPO^} summary/q" README.md +# add a newline after listing section +echo >> README.md +# loop over path of modules tree +for path in $(find -mindepth 1 -type d ! -path '*/.*' ! -path './scripts*' ! -path './common/module' -print | sort -fdbi); do + # split path in directories + directories=($(list_dirs $path)) + # loop over directories in path + for i in $(seq 1 $((${#directories[@]}-1))); do + ## add tabulation for every subdirectory + echo -en "\t" >> README.md + done + # add link to list of modules + echo -en "- [$(basename ${path})](https://github.com/claranet/terraform-datadog-${REPO}/tree/master/" >> README.md + # add path to link + for directory in "${directories[@]}"; do + echo -en "${directory}/" >> README.md + done + # end of markdown link + echo ")" >> README.md +done diff --git a/.terraform/modules/datadog-message-alerting-bh-only/scripts/20_update_modules_readmes.sh b/.terraform/modules/datadog-message-alerting-bh-only/scripts/20_update_modules_readmes.sh new file mode 100755 index 0000000..64d34ff --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/scripts/20_update_modules_readmes.sh @@ -0,0 +1,119 @@ +#!/bin/bash + +source "$(dirname $0)/utils.sh" +init +echo "Update README.md for every ${REPO} modules" + +# this is the pattern from where custom information is saved to be restored +PATTERN_DOC="Related documentation" + +# loop over every modules +for module in $(browse_modules "$(get_scope ${1:-})" "${REPO}-*.tf"); do + echo -e "\t- Generate README.md for module: ${module}" + cd ${module} + EXIST=0 + if [ -f README.md ]; then + mv README.md README.md.bak + EXIST=1 + fi + # module name from path + module_space=$(list_dirs ${module}) + # module name with space as separator + module_upper=${module_space^^} + # module name with dash as separator + module_dash=${module_space//[ ]/-} + # module name with slash as separator + module_slash=${module_space//[ ]/\/} + + # (re)generate README from scratch + cat < README.md +# ${module_upper} DataDog ${REPO} + +## How to use this module + +\`\`\`hcl +module "datadog-${REPO}-${module_dash}" { + source = "claranet/${REPO}/datadog//${module_slash}" + version = "{revision}" +EOF + + append="" + list="" + last_argument="version" + if [ "${REPO}" == "monitors" ]; then + cat <> README.md + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +EOF + last_argument="message" + set +e + IFS='' read -r -d '' append < /dev/null + cd - >> /dev/null +done diff --git a/.terraform/modules/datadog-message-alerting-bh-only/scripts/30_update_module.sh b/.terraform/modules/datadog-message-alerting-bh-only/scripts/30_update_module.sh new file mode 100755 index 0000000..7caa669 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/scripts/30_update_module.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +source "$(dirname $0)/utils.sh" +init +if [ "${REPO}" != "monitors" ]; then + # Run this script only for monitors repo + exit 0 +fi +echo "Generate outputs.tf files when does not exist for every monitors modules" +root=$(basename ${PWD}) + +# loop over every modules +for module in $(browse_modules "$(get_scope ${1:-})" "${REPO}-*.tf"); do + cd ${module} + # get name of the monitors set directory + resource="$(basename ${module})" + # if modules.tf does not exist AND if this set respect our tagging convention + if ! [ -f modules.tf ] && grep -q filter_tags_use_defaults inputs.tf; then + echo -e "\t- Generate modules.tf for module: ${module}" + relative="" + current="${PWD}" + # iterate on path until we go back to root + while [[ "$(basename $current)" != "$root" ]]; do + # for each iteration add "../" to generate relative path + relative="${relative}../" + # remove last directory from current path + current="$(dirname $current)" + done + # add the filter tags module + cat > modules.tf <> /dev/null +done diff --git a/.terraform/modules/datadog-message-alerting-bh-only/scripts/90_best_practices.sh b/.terraform/modules/datadog-message-alerting-bh-only/scripts/90_best_practices.sh new file mode 100755 index 0000000..4dc2ddc --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/scripts/90_best_practices.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +source "$(dirname $0)/utils.sh" +init +if [ "${REPO}" != "monitors" ]; then + # Run this script only for monitors repo + exit 0 +fi +echo "Check best practices respect" + +echo -e "\t- Check only one notify_no_data set to true per module" +# loop over every modules +for module in $(browse_modules "$(get_scope ${1:-})" "${REPO}-*.tf"); do + # check if there is more than 1 notify_no_data not set to false. + # here the risk to check is the possible "true" value while this could lead the duplicated no data alerts. + # every metrics from one module come from the same source so this does not make sens to check no data for multiple monitors in the same module. + if [[ $(cat ${module}/monitors-*.tf | grep 'notify_no_data[[:space:]]*=' | grep -cv '=[[:space:]]*false') -gt 1 ]]; then + echo "More than one notify_no_data not set to \"false\" in $module" + exit 1 + fi +done diff --git a/.terraform/modules/datadog-message-alerting-bh-only/scripts/99_terraform.sh b/.terraform/modules/datadog-message-alerting-bh-only/scripts/99_terraform.sh new file mode 100755 index 0000000..b4959ca --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/scripts/99_terraform.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +source "$(dirname $0)/utils.sh" +init +echo "Check terraform CI" + +# Clean when exit +err() { + rm -f "${module}/tmp.tf" +} +trap 'err $LINENO' ERR TERM EXIT INT + +provider_version=$(grep -m1 ^[[:space:]]*version[[:space:]]= README.md | awk '{print $3}') + +# loop over every modules +for module in $(browse_modules "$(get_scope ${1:-})" 'inputs.tf'); do + echo -e "\t- Terraform validate on module: ${module}" + if [[ ${module} != ./common/* ]]; then + cat < ${module}/tmp.tf +provider "datadog" { + api_key = var.datadog_api_key + app_key = var.datadog_app_key +} + +variable "datadog_api_key" { + type = string + default = "xxx" +} + +variable "datadog_app_key" { + type = string + default = "yyy" +} + +EOF + + if ! [ -f ${module}/versions.tf ]; then + cp ./common/module/versions.tf ${module}/ + fi + fi + + if [ -f ${module}/test.tf.ci ]; then + cat ${module}/test.tf.ci >> ${module}/tmp.tf + fi + terraform -chdir=${module} init > /tmp/null + terraform -chdir=${module} validate + rm -f ${module}/tmp.tf +done + +echo -e "\t- Terraform fmt recursive" +terraform fmt -recursive + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/scripts/README.md b/.terraform/modules/datadog-message-alerting-bh-only/scripts/README.md new file mode 100755 index 0000000..25e4d00 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/scripts/README.md @@ -0,0 +1,65 @@ +# Datadog scripts + +## Summary + +This repository contains a `scripts` directory where there are multiple scripts helping to different things: + +- help and automate for some boring and repetitive tasks. +- keep everything up to date and warn if you forget. +- compliant checks and ensure best practices are respected. +- code validation for continuous integration. + +## Structure + +There are two kinds of scripts naming: + +- `[0-9][0-9]_script_name.sh`: will be automatically run by `auto_update.sh` wrapper. +- `script_name.sh`: should be run manually. + +Here is a list of scripts and their purpose: + +- `auto_update.sh`: is the most important and the one the must used. It is a simple wrapper which will calls every other `[0-9][0-9]*` scripts. + - It should be run by contributor after every change. + - The CI will also run it and it will fail if it detects any change compared to commit. + - "Children" scripts could be run individually if you know exactly what you need to update after a change. + - This script all "children" scripts takes one optional parameter to limit execution to a specific sub path. Else this will run on all directories. +- `00_requirements.sh`: check some requirements like `terraform` command exists before run other scripts. +- `10_update_output.sh`: will generate and update all `outputs.tf`. +- `20_update_global_readme.sh`: will update the main `README.md` file and generate the list of all modules browsing the repository. +- `20_update_modules_readmes.sh`: will create and update `README.md` for each module. It will save all manual changes below `## Related documentation` section. +- `30_update_module.sh`: will create `modules.tf` file per module when does not exist. +- `90_best_practices.sh`: will check compliance and best practices respect. +- `99_terraform.sh`: terraform CI (init & validate only while auto apply is done in another pipeline). +- `utils.sh`: contains useful functions common to multiple scripts. It is not attended to be run. +- `changelog.sh`: helper script to release a new version. + - generate and update `CHANGELOG.md` file from git history. + - filter to list only "done" issues from JIRA. + - close all issues on JIRA. + - fix version for all issues on JIRA. + - create release for current version on JIRA. + +## Usage + +First, you need to retrieve `scripts` repository by cloning submodules: + +``` +git submodule update --init +``` + +After any change on this repo, you will need to run the `./scripts/auto_update.sh [PATH_TO_MODULE]` command to make sure all is up to date otherwise the CI pipeline will fail. +The parameter is optional and it will limit the scripts execution on a specific path on the repository. + +On linux system it is possible to run the script directly while `terraform`, `terraform-docs`, `terraform-config-inspect`, `jq` commands are available in your `PATH`. +Otherwise you can use [the same docker image as the CI](https://hub.docker.com/r/claranet/terraform-ci) on every other platforms. + + +``` +# if you already pulled the container once, you will need to update it +$ docker pull claranet/terraform-ci +# then just need to run the script of your choice with optional path parameter or not +$ docker run --rm -v "$PWD:/work" claranet/terraform-ci /work/scripts/auto_update.sh +# else if you run docker in version >= 19.09 (or nightly builds) so you can do it both in one command +$ docker run --pull=always --rm -v "$PWD:/work" claranet/terraform-ci /work/scripts/auto_update.sh +# it is also possible to run the scripts in debug in case of silent fail +$ docker run -e GITLAB_CI=true --rm -v "$PWD:/work" claranet/terraform-ci /work/scripts/auto_update.sh +``` diff --git a/.terraform/modules/datadog-message-alerting-bh-only/scripts/auto_update.sh b/.terraform/modules/datadog-message-alerting-bh-only/scripts/auto_update.sh new file mode 100755 index 0000000..3371f04 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/scripts/auto_update.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +source "$(dirname $0)/utils.sh" +init scripts + +for script in [0-9][0-9]_*.sh; do + ./${script} "$(get_scope ${1:-})" +done diff --git a/.terraform/modules/datadog-message-alerting-bh-only/scripts/changelog.sh b/.terraform/modules/datadog-message-alerting-bh-only/scripts/changelog.sh new file mode 100755 index 0000000..3a8e03f --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/scripts/changelog.sh @@ -0,0 +1,145 @@ +#/bin/bash +set -euo pipefail + +source "$(dirname $0)/utils.sh" +goto_root + +## Check parameters and environment variables +# PARAMETER: The next version to release (i.e. v3.0.0) +# JIRA_API_TOKEN: the user api token to login jira +# JIRA_LOGIN: the user email to login on jira + +if [ $# -eq 0 ]; then + echo "Target tag is required as parameter" + exit 1 +fi + +if [ -z ${JIRA_API_TOKEN:-} ]; then + echo "Environment variable JIRA_API_TOKEN needs to be defined: https://confluence.atlassian.com/cloud/api-tokens-938839638.html" + exit 2 +fi + +if [ -z ${JIRA_LOGIN:-} ]; then + echo "Environment variable JIRA_LOGIN needs to be defined: jira user email" + exit 3 +fi + +if ! command -v jira >/dev/null; then + echo "go-jira command is required: https://github.com/go-jira/jira#install" +fi + +TAG_TARGET=$1 +TAG_SOURCE=${TAG_SOURCE:-$(git describe --tags --abbrev=0)} +JIRA_ENDPOINT=${JIRA_ENDPOINT:-https://claranet-morea.atlassian.net} +JIRA_STATUS=${JIRA_STATUS:-Done Closed} +SAVEIFS=$IFS +IFS=$(echo -en "\n\b") +TMP=$(mktemp -d) + +# Clean when exit +err() { + rm -fr ${TMP} + IFS=$SAVEIFS +} +trap 'err $LINENO' ERR TERM EXIT INT + +# Create the go-jira template with issue, status and summary as CSV +mkdir -p ${HOME}/.jira.d/templates +cat > ${HOME}/.jira.d/templates/changelog < ${HOME}/.jira.d/templates/versions <> ${HOME}/.jira.d/templates/fixversion < $TMP_ISSUES + +TMP_INFO_ISSUES=${TMP}/info-issues.txt +for issue in $(cat $TMP_ISSUES); do + # retrieve jira information from go-jira template + jira --endpoint=${JIRA_ENDPOINT} --login=${JIRA_LOGIN} view $issue --template=changelog +done | sort > $TMP_INFO_ISSUES + +TMP_TREATED_ISSUES=${TMP}/treated-issues.txt +TMP_CHANGELOG=${TMP}/changelog.md +# init changelog for next version +echo -e "\n# $TAG_TARGET ($(LANG=eng date +"%B %d, %Y"))" >> $TMP_CHANGELOG +for line in $(cat $TMP_INFO_ISSUES); do + # retrieve jira information from go-jira template + IFS=';' read -r type issue status summary <<< $line + # Ignore if issue is not in required status + if ! [[ "$JIRA_STATUS" == *"$status"* ]]; then + echo "Issue $issue with status \"$status\" not in [$JIRA_STATUS] ($summary)" + read -p 'Would you like to transition issue to "Done" status ? if no, the issue will be ignored ([y]/n): ' -r answer + if [[ "$answer" != "n" ]]; then + if [[ "$status" == "Qualif" ]]; then + jira --endpoint=${JIRA_ENDPOINT} --login=${JIRA_LOGIN} transition "Approve" $issue --noedit > /dev/null + status="To Do" + fi + if [[ "$status" == "To Do" ]]; then + jira --endpoint=${JIRA_ENDPOINT} --login=${JIRA_LOGIN} transition "In Progress" $issue --noedit > /dev/null + status="In Progress" + fi + if [[ "$status" == "In Progress" ]]; then + jira --endpoint=${JIRA_ENDPOINT} --login=${JIRA_LOGIN} transition "Review" $issue --noedit > /dev/null + status="In Review" + fi + if [[ "$status" == "In Review" ]]; then + jira --endpoint=${JIRA_ENDPOINT} --login=${JIRA_LOGIN} transition "Done" $issue --noedit > /dev/null + fi + fi + fi + # add line for type only once + if ! grep -q "^## $type" $TMP_CHANGELOG; then + echo -e "\n## $type\n" >> $TMP_CHANGELOG + fi + # add jira issue line to changelog + echo "* [[$issue](${JIRA_ENDPOINT}/browse/${issue})] - $summary" >> $TMP_CHANGELOG + echo $issue >> $TMP_TREATED_ISSUES +done + +cat $TMP_CHANGELOG +# Ask for confirmation to update changelog +read -p 'Update CHANGELOG.md with this ? (y/[n]): ' -r answer +if [[ "$answer" == "y" ]]; then + separator='\n' + # Remove target tag changelog if already exist + if grep -q $TAG_TARGET CHANGELOG.md; then + prev_tag=$(grep '^# v' CHANGELOG.md | sed -n 2p) + sed -i "/${prev_tag}/,\$!d" CHANGELOG.md + separator="${separator}\n" + fi + # Add target tag changelog to final changelog + echo -e "$(cat $TMP_CHANGELOG)${separator}$(cat CHANGELOG.md)" > CHANGELOG.md +fi + +read -p "Close all issues and fix version $TAG_TARGET ? (y/[n]): " -r answer +if [[ "$answer" == "y" ]]; then + # Create version if does not exists + one_issue=$(head -n 1 $TMP_TREATED_ISSUES) + auth_header=$(printf "${JIRA_LOGIN}:${JIRA_API_TOKEN}" | base64) + if ! jira --endpoint=${JIRA_ENDPOINT} --login=${JIRA_LOGIN} editmeta $one_issue --template=versions | grep -q $TAG_TARGET; then + curl -H "Authorization: Basic $auth_header" -H "Content-Type: application/json" -X POST -d "{\"name\": \"${TAG_TARGET}\",\"userReleaseDate\": \"$(echo -n $(LANG=eng date +'%-d/%b/%Y'))\",\"project\": \"$(echo -n $one_issue | cut -d'-' -f1)\",\"archived\": false,\"released\": true}" ${JIRA_ENDPOINT}/rest/api/latest/version + fi + for issue in $(cat $TMP_TREATED_ISSUES); do + jira --endpoint=${JIRA_ENDPOINT} --login=${JIRA_LOGIN} transition "Close" $issue --noedit > /dev/null 2>&1 && echo "OK $issue closed" || echo "OK $issue already closed" + jira --endpoint=${JIRA_ENDPOINT} --login=${JIRA_LOGIN} edit $issue --template=fixversion --override fixVersions=${TAG_TARGET} --noedit > /dev/null && echo "OK $issue fix version $TAG_TARGET" + done +fi diff --git a/.terraform/modules/datadog-message-alerting-bh-only/scripts/utils.sh b/.terraform/modules/datadog-message-alerting-bh-only/scripts/utils.sh new file mode 100755 index 0000000..a419cb1 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/scripts/utils.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +function goto_root() { + script_dir=$(dirname $0) + if [[ "$script_dir" == "." ]]; then + cd .. + else + cd "$(dirname $script_dir)" + fi +} + +function init() { + set -euo pipefail + if [[ ${GITLAB_CI:-} == "true" ]]; then + set -x + fi + # MON-478 fix sort order behavior on case + export LC_COLLATE=C + goto_root + if ! [ -z ${1:-} ]; then + cd "$1" + fi + REPO="integrations" + if head -n1 ./README.md | grep -q -i monitors; then + REPO="monitors" + fi +} + +function get_scope() { + TO_PARSE="./" + if [ ! -z ${1+x} ] && [ $1 != "." ]; then + TO_PARSE="$1" + fi + if [[ $TO_PARSE != ./* ]]; then + TO_PARSE="./${TO_PARSE}" + fi + echo $TO_PARSE +} + +function list_dirs() { + echo ${1} | awk -F '/' '{$1=""; print $0}' | cut -c 2- +} + +function browse_modules() { + find "$1" -name "$2" -exec dirname "{}" \; | sort -fdbiu +} + +function get_name() { + regex='^[[:space:]]+name[[:space:]]+=[[:space:]]+"\$.*\[.*\][[:space:]]+(.*)"$' + if [[ "${1}" =~ ${regex} ]]; then + name="${BASH_REMATCH[1]}" + else + echo "Error: impossible to parse monitor name" + return 42 + fi + if [[ "${name}" =~ ^(.*)[[:space:]]\{\{#is_alert\}\}.*$ ]]; then + name="${BASH_REMATCH[1]}" + fi + echo $name + return 0 +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/system/generic/README.md b/.terraform/modules/datadog-message-alerting-bh-only/system/generic/README.md new file mode 100755 index 0000000..0c4aca4 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/system/generic/README.md @@ -0,0 +1,134 @@ +# SYSTEM GENERIC DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-system-generic" { + source = "claranet/monitors/datadog//system/generic" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message + + memory_message = "${module.datadog-message-alerting-bh-only.alerting-message}" +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- CPU load 5 ratio +- CPU usage +- Disk inodes usage +- Disk space usage +- Disk Space usage forecast +- Usable Memory + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | +| [filter-tags-disk](#module\_filter-tags-disk) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cpu](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.disk_inodes](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.disk_space](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.disk_space_forecast](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.load](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.memory](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_enabled](#input\_cpu\_enabled) | Flag to enable CPU high monitor | `string` | `"true"` | no | +| [cpu\_extra\_tags](#input\_cpu\_extra\_tags) | Extra tags for CPU high monitor | `list(string)` | `[]` | no | +| [cpu\_message](#input\_cpu\_message) | Custom message for CPU high monitor | `string` | `""` | no | +| [cpu\_threshold\_critical](#input\_cpu\_threshold\_critical) | CPU high critical threshold | `number` | `90` | no | +| [cpu\_threshold\_warning](#input\_cpu\_threshold\_warning) | CPU high warning threshold | `number` | `85` | no | +| [cpu\_time\_aggregator](#input\_cpu\_time\_aggregator) | Monitor aggregator for CPU high [available values: min, max or avg] | `string` | `"min"` | no | +| [cpu\_timeframe](#input\_cpu\_timeframe) | Monitor timeframe for CPU high [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1h"` | no | +| [disk\_inodes\_enabled](#input\_disk\_inodes\_enabled) | Flag to enable Free disk inodes monitor | `string` | `"true"` | no | +| [disk\_inodes\_extra\_tags](#input\_disk\_inodes\_extra\_tags) | Extra tags for Free disk inodes monitor | `list(string)` | `[]` | no | +| [disk\_inodes\_message](#input\_disk\_inodes\_message) | Custom message for Free disk inodes monitor | `string` | `""` | no | +| [disk\_inodes\_threshold\_critical](#input\_disk\_inodes\_threshold\_critical) | Free disk space critical threshold | `number` | `95` | no | +| [disk\_inodes\_threshold\_warning](#input\_disk\_inodes\_threshold\_warning) | Free disk space warning threshold | `number` | `90` | no | +| [disk\_inodes\_time\_aggregator](#input\_disk\_inodes\_time\_aggregator) | Monitor aggregator for Free disk inodes [available values: min, max or avg] | `string` | `"min"` | no | +| [disk\_inodes\_timeframe](#input\_disk\_inodes\_timeframe) | Monitor timeframe for Free disk inodes [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [disk\_space\_enabled](#input\_disk\_space\_enabled) | Flag to enable Free diskspace monitor | `string` | `"true"` | no | +| [disk\_space\_extra\_tags](#input\_disk\_space\_extra\_tags) | Extra tags for Free diskspace monitor | `list(string)` | `[]` | no | +| [disk\_space\_forecast\_algorithm](#input\_disk\_space\_forecast\_algorithm) | Algorithm for the Free diskspace Forecast monitor [available values: `linear` or `seasonal`] | `string` | `"linear"` | no | +| [disk\_space\_forecast\_deviations](#input\_disk\_space\_forecast\_deviations) | Deviations for the Free diskspace Forecast monitor [available values: `1`, `2`, `3`, `4` or `5`] | `string` | `1` | no | +| [disk\_space\_forecast\_enabled](#input\_disk\_space\_forecast\_enabled) | Flag to enable Free diskspace forecast monitor | `string` | `"true"` | no | +| [disk\_space\_forecast\_extra\_tags](#input\_disk\_space\_forecast\_extra\_tags) | Extra tags for Free diskspace forecast monitor | `list(string)` | `[]` | no | +| [disk\_space\_forecast\_interval](#input\_disk\_space\_forecast\_interval) | Interval for the Free diskspace Forecast monitor [available values: `30m`, `60m` or `120m`] | `string` | `"60m"` | no | +| [disk\_space\_forecast\_linear\_history](#input\_disk\_space\_forecast\_linear\_history) | History for the Free diskspace Forecast monitor [available values: `12h`, `#d` (1, 2, or 3), `#w` (1, or 2) or `#mo` (1, 2 or 3)] | `string` | `"1w"` | no | +| [disk\_space\_forecast\_linear\_model](#input\_disk\_space\_forecast\_linear\_model) | Model for the Free diskspace Forecast monitor [available values: `default`, `simple` or `reactive`] | `string` | `"default"` | no | +| [disk\_space\_forecast\_message](#input\_disk\_space\_forecast\_message) | Custom message for Free diskspace forecast monitor | `string` | `""` | no | +| [disk\_space\_forecast\_seasonal\_seasonality](#input\_disk\_space\_forecast\_seasonal\_seasonality) | Seasonality for the Free diskspace Forecast monitor | `string` | `"weekly"` | no | +| [disk\_space\_forecast\_threshold\_critical](#input\_disk\_space\_forecast\_threshold\_critical) | Free disk space forecast critical threshold | `number` | `80` | no | +| [disk\_space\_forecast\_threshold\_critical\_recovery](#input\_disk\_space\_forecast\_threshold\_critical\_recovery) | Free disk space forecast recovery threshold | `number` | `72` | no | +| [disk\_space\_forecast\_time\_aggregator](#input\_disk\_space\_forecast\_time\_aggregator) | Monitor aggregator for Free diskspace forecast [available values: min, max or avg] | `string` | `"max"` | no | +| [disk\_space\_forecast\_timeframe](#input\_disk\_space\_forecast\_timeframe) | Monitor timeframe for Free diskspace forecast [available values: `next_12h`, `next_#d` (1, 2, or 3), `next_#w` (1 or 2) or `next_#mo` (1, 2 or 3)] | `string` | `"next_1w"` | no | +| [disk\_space\_message](#input\_disk\_space\_message) | Custom message for Free diskspace monitor | `string` | `""` | no | +| [disk\_space\_threshold\_critical](#input\_disk\_space\_threshold\_critical) | Free disk space critical threshold | `number` | `90` | no | +| [disk\_space\_threshold\_warning](#input\_disk\_space\_threshold\_warning) | Free disk space warning threshold | `number` | `80` | no | +| [disk\_space\_time\_aggregator](#input\_disk\_space\_time\_aggregator) | Monitor aggregator for Free diskspace [available values: min, max or avg] | `string` | `"max"` | no | +| [disk\_space\_timeframe](#input\_disk\_space\_timeframe) | Monitor timeframe for Free diskspace [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [load\_enabled](#input\_load\_enabled) | Flag to enable CPU load ratio monitor | `string` | `"true"` | no | +| [load\_extra\_tags](#input\_load\_extra\_tags) | Extra tags for CPU load ratio monitor | `list(string)` | `[]` | no | +| [load\_message](#input\_load\_message) | Custom message for CPU load ratio monitor | `string` | `""` | no | +| [load\_threshold\_critical](#input\_load\_threshold\_critical) | CPU load ratio critical threshold | `number` | `2.5` | no | +| [load\_threshold\_warning](#input\_load\_threshold\_warning) | CPU load ratio warning threshold | `number` | `2` | no | +| [load\_time\_aggregator](#input\_load\_time\_aggregator) | Monitor aggregator for CPU load ratio [available values: min, max or avg] | `string` | `"min"` | no | +| [load\_timeframe](#input\_load\_timeframe) | Monitor timeframe for CPU load ratio [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_30m"` | no | +| [memory\_enabled](#input\_memory\_enabled) | Flag to enable Free memory monitor | `string` | `"true"` | no | +| [memory\_extra\_tags](#input\_memory\_extra\_tags) | Extra tags for Free memory monitor | `list(string)` | `[]` | no | +| [memory\_message](#input\_memory\_message) | Mandatory message for Free memory monitor to avoid NBH alerting by default | `string` | n/a | yes | +| [memory\_threshold\_critical](#input\_memory\_threshold\_critical) | Free disk space critical threshold | `number` | `5` | no | +| [memory\_threshold\_warning](#input\_memory\_threshold\_warning) | Free disk space warning threshold | `number` | `10` | no | +| [memory\_time\_aggregator](#input\_memory\_time\_aggregator) | Monitor aggregator for Free memory [available values: min, max or avg] | `string` | `"max"` | no | +| [memory\_timeframe](#input\_memory\_timeframe) | Monitor timeframe for Free memory [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cpu\_id](#output\_cpu\_id) | id for monitor cpu | +| [disk\_inodes\_id](#output\_disk\_inodes\_id) | id for monitor disk\_inodes | +| [disk\_space\_forecast\_id](#output\_disk\_space\_forecast\_id) | id for monitor disk\_space\_forecast | +| [disk\_space\_id](#output\_disk\_space\_id) | id for monitor disk\_space | +| [load\_id](#output\_load\_id) | id for monitor load | +| [memory\_id](#output\_memory\_id) | id for monitor memory | +## Related documentation + +DataDog documentation: diff --git a/.terraform/modules/datadog-message-alerting-bh-only/system/generic/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/system/generic/inputs.tf new file mode 100755 index 0000000..538fc75 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/system/generic/inputs.tf @@ -0,0 +1,323 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# System generic specific + +variable "cpu_enabled" { + description = "Flag to enable CPU high monitor" + type = string + default = "true" +} + +variable "cpu_extra_tags" { + description = "Extra tags for CPU high monitor" + type = list(string) + default = [] +} + +variable "cpu_message" { + description = "Custom message for CPU high monitor" + type = string + default = "" +} + +variable "cpu_time_aggregator" { + description = "Monitor aggregator for CPU high [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cpu_timeframe" { + description = "Monitor timeframe for CPU high [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1h" +} + +variable "cpu_threshold_warning" { + description = "CPU high warning threshold" + default = 85 +} + +variable "cpu_threshold_critical" { + description = "CPU high critical threshold" + default = 90 +} + +variable "load_enabled" { + description = "Flag to enable CPU load ratio monitor" + type = string + default = "true" +} + +variable "load_extra_tags" { + description = "Extra tags for CPU load ratio monitor" + type = list(string) + default = [] +} + +variable "load_message" { + description = "Custom message for CPU load ratio monitor" + type = string + default = "" +} + +variable "load_time_aggregator" { + description = "Monitor aggregator for CPU load ratio [available values: min, max or avg]" + type = string + default = "min" +} + +variable "load_timeframe" { + description = "Monitor timeframe for CPU load ratio [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_30m" +} + +variable "load_threshold_warning" { + description = "CPU load ratio warning threshold" + default = 2 +} + +variable "load_threshold_critical" { + description = "CPU load ratio critical threshold" + default = 2.5 +} + +variable "disk_space_enabled" { + description = "Flag to enable Free diskspace monitor" + type = string + default = "true" +} + +variable "disk_space_extra_tags" { + description = "Extra tags for Free diskspace monitor" + type = list(string) + default = [] +} + +variable "disk_space_message" { + description = "Custom message for Free diskspace monitor" + type = string + default = "" +} + +variable "disk_space_time_aggregator" { + description = "Monitor aggregator for Free diskspace [available values: min, max or avg]" + type = string + default = "max" +} + +variable "disk_space_timeframe" { + description = "Monitor timeframe for Free diskspace [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "disk_space_threshold_warning" { + description = "Free disk space warning threshold" + default = 80 +} + +variable "disk_space_threshold_critical" { + description = "Free disk space critical threshold" + default = 90 +} + +variable "disk_space_forecast_enabled" { + description = "Flag to enable Free diskspace forecast monitor" + type = string + default = "true" +} + +variable "disk_space_forecast_extra_tags" { + description = "Extra tags for Free diskspace forecast monitor" + type = list(string) + default = [] +} + +variable "disk_space_forecast_message" { + description = "Custom message for Free diskspace forecast monitor" + type = string + default = "" +} + +variable "disk_space_forecast_time_aggregator" { + description = "Monitor aggregator for Free diskspace forecast [available values: min, max or avg]" + type = string + default = "max" +} + +variable "disk_space_forecast_timeframe" { + description = "Monitor timeframe for Free diskspace forecast [available values: `next_12h`, `next_#d` (1, 2, or 3), `next_#w` (1 or 2) or `next_#mo` (1, 2 or 3)]" + type = string + default = "next_1w" +} + +variable "disk_space_forecast_algorithm" { + description = "Algorithm for the Free diskspace Forecast monitor [available values: `linear` or `seasonal`]" + type = string + default = "linear" +} + +variable "disk_space_forecast_deviations" { + description = "Deviations for the Free diskspace Forecast monitor [available values: `1`, `2`, `3`, `4` or `5`]" + type = string + default = 1 +} + +variable "disk_space_forecast_interval" { + description = "Interval for the Free diskspace Forecast monitor [available values: `30m`, `60m` or `120m`]" + type = string + default = "60m" +} + +variable "disk_space_forecast_linear_history" { + description = "History for the Free diskspace Forecast monitor [available values: `12h`, `#d` (1, 2, or 3), `#w` (1, or 2) or `#mo` (1, 2 or 3)]" + type = string + default = "1w" +} + +variable "disk_space_forecast_linear_model" { + description = "Model for the Free diskspace Forecast monitor [available values: `default`, `simple` or `reactive`]" + type = string + default = "default" +} + +variable "disk_space_forecast_seasonal_seasonality" { + description = "Seasonality for the Free diskspace Forecast monitor" + type = string + default = "weekly" +} + +variable "disk_space_forecast_threshold_critical_recovery" { + description = "Free disk space forecast recovery threshold" + default = 72 +} + +variable "disk_space_forecast_threshold_critical" { + description = "Free disk space forecast critical threshold" + default = 80 +} + +variable "disk_inodes_enabled" { + description = "Flag to enable Free disk inodes monitor" + type = string + default = "true" +} + +variable "disk_inodes_extra_tags" { + description = "Extra tags for Free disk inodes monitor" + type = list(string) + default = [] +} + +variable "disk_inodes_message" { + description = "Custom message for Free disk inodes monitor" + type = string + default = "" +} + +variable "disk_inodes_time_aggregator" { + description = "Monitor aggregator for Free disk inodes [available values: min, max or avg]" + type = string + default = "min" +} + +variable "disk_inodes_timeframe" { + description = "Monitor timeframe for Free disk inodes [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "disk_inodes_threshold_warning" { + description = "Free disk space warning threshold" + default = 90 +} + +variable "disk_inodes_threshold_critical" { + description = "Free disk space critical threshold" + default = 95 +} + +variable "memory_enabled" { + description = "Flag to enable Free memory monitor" + type = string + default = "true" +} + +variable "memory_extra_tags" { + description = "Extra tags for Free memory monitor" + type = list(string) + default = [] +} + +variable "memory_message" { + description = "Mandatory message for Free memory monitor to avoid NBH alerting by default" + type = string +} + +variable "memory_time_aggregator" { + description = "Monitor aggregator for Free memory [available values: min, max or avg]" + type = string + default = "max" +} + +variable "memory_timeframe" { + description = "Monitor timeframe for Free memory [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "memory_threshold_warning" { + description = "Free disk space warning threshold" + default = 10 +} + +variable "memory_threshold_critical" { + description = "Free disk space critical threshold" + default = 5 +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/system/generic/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/system/generic/modules.tf new file mode 100755 index 0000000..fc2e056 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/system/generic/modules.tf @@ -0,0 +1,21 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "system" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + +module "filter-tags-disk" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "system" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["dd_disk:enabled"] +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/system/generic/monitors-system.tf b/.terraform/modules/datadog-message-alerting-bh-only/system/generic/monitors-system.tf new file mode 100755 index 0000000..0440aaa --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/system/generic/monitors-system.tf @@ -0,0 +1,183 @@ +resource "datadog_monitor" "cpu" { + count = var.cpu_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] CPU usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cpu_message, var.message) + type = "query alert" + + query = < ${var.cpu_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.cpu_threshold_warning + critical = var.cpu_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:system", "provider:system-check", "resource:generic", "team:claranet", "created-by:terraform"], var.cpu_extra_tags) +} + +resource "datadog_monitor" "load" { + count = var.load_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] CPU load 5 ratio {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.load_message, var.message) + type = "query alert" + + query = < ${var.load_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.load_threshold_warning + critical = var.load_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:system", "provider:system-core", "resource:generic", "team:claranet", "created-by:terraform"], var.load_extra_tags) +} + +resource "datadog_monitor" "disk_space" { + count = var.disk_space_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Disk space usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.disk_space_message, var.message) + type = "query alert" + + query = < ${var.disk_space_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.disk_space_threshold_warning + critical = var.disk_space_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:system", "provider:disk", "resource:generic", "team:claranet", "created-by:terraform"], var.disk_space_extra_tags) +} + +resource "datadog_monitor" "disk_space_forecast" { + count = var.disk_space_forecast_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Disk Space usage could reach {{#is_alert}}{{threshold}}%%{{/is_alert}} in a near future" + message = coalesce(var.disk_space_forecast_message, var.message) + type = "query alert" + + query = <= ${var.disk_space_forecast_threshold_critical} +EOQ + + monitor_thresholds { + critical_recovery = var.disk_space_forecast_threshold_critical_recovery + critical = var.disk_space_forecast_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = true + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:system", "provider:disk", "resource:generic", "team:claranet", "created-by:terraform"], var.disk_space_forecast_extra_tags) +} + +resource "datadog_monitor" "disk_inodes" { + count = var.disk_inodes_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Disk inodes usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.disk_inodes_message, var.message) + type = "query alert" + + query = < ${var.disk_inodes_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.disk_inodes_threshold_warning + critical = var.disk_inodes_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:system", "provider:disk", "resource:generic", "team:claranet", "created-by:terraform"], var.disk_inodes_extra_tags) +} + +resource "datadog_monitor" "memory" { + count = var.memory_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Usable Memory {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = var.memory_message + type = "query alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.host_unreachable](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [unreachable\_enabled](#input\_unreachable\_enabled) | Flag to enable Host unreachable monitor | `string` | `"true"` | no | +| [unreachable\_extra\_tags](#input\_unreachable\_extra\_tags) | Extra tags for Host unreachable monitor | `list(string)` | `[]` | no | +| [unreachable\_message](#input\_unreachable\_message) | Custom message for Host unreachable monitor | `string` | `""` | no | +| [unreachable\_no\_data\_timeframe](#input\_unreachable\_no\_data\_timeframe) | Timeframe for Host unreachable monitor to alert on no data | `string` | `20` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [host\_unreachable\_id](#output\_host\_unreachable\_id) | id for monitor host\_unreachable | +## Related documentation + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/system/unreachable/inputs.tf b/.terraform/modules/datadog-message-alerting-bh-only/system/unreachable/inputs.tf new file mode 100755 index 0000000..d0388dc --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/system/unreachable/inputs.tf @@ -0,0 +1,72 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Unreachable + +variable "unreachable_enabled" { + description = "Flag to enable Host unreachable monitor" + type = string + default = "true" +} + +variable "unreachable_extra_tags" { + description = "Extra tags for Host unreachable monitor" + type = list(string) + default = [] +} + +variable "unreachable_message" { + description = "Custom message for Host unreachable monitor" + type = string + default = "" +} + +variable "unreachable_no_data_timeframe" { + description = "Timeframe for Host unreachable monitor to alert on no data" + type = string + default = 20 +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/system/unreachable/modules.tf b/.terraform/modules/datadog-message-alerting-bh-only/system/unreachable/modules.tf new file mode 100755 index 0000000..4c44673 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/system/unreachable/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "system" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-message-alerting-bh-only/system/unreachable/monitors-unreachable.tf b/.terraform/modules/datadog-message-alerting-bh-only/system/unreachable/monitors-unreachable.tf new file mode 100755 index 0000000..1af06c9 --- /dev/null +++ b/.terraform/modules/datadog-message-alerting-bh-only/system/unreachable/monitors-unreachable.tf @@ -0,0 +1,28 @@ +resource "datadog_monitor" "host_unreachable" { + count = var.unreachable_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Host unreachable" + message = coalesce(var.unreachable_message, var.message) + type = "service check" + + query = <= v4.0.0`. + +# v3.6.0 (January 27, 2021) + +## Improvement + +* Add monitor for Google Cloud Platform Memorystore Redis system memory usage ratio +* [[MN-587](https://onejira.atlassian.net/browse/MN-587)] - MN-587 Add ProxySQL monitors + +# v3.5.0 (August 27, 2020) + +## Bug + +* [[MN-581](https://onejira.atlassian.net/browse/MN-581)] - repair CI now pt-monitoring is dead + +## Improvement + +* [[MN-580](https://onejira.atlassian.net/browse/MN-580)] - Terraform 0.13 compatibility for datadog modules + +# v3.4.0 (March 30, 2020) + +## Bug + +* [[MN-574](https://onejira.atlassian.net/browse/MN-574)] - Fix k8s pod phases status + +## Improvement + +* [[MN-563](https://onejira.atlassian.net/browse/MN-563)] - TFenv support +* [[MN-571](https://onejira.atlassian.net/browse/MN-571)] - Azure AppGateway change metric + +## New Feature + +* [[MN-221](https://onejira.atlassian.net/browse/MN-221)] - Monitors for Zookeeper +* [[MN-496](https://onejira.atlassian.net/browse/MN-496)] - Customize the group by on the monitors + +# v3.3.0 (January 23, 2020) + +## Bug + +* [[MN-556](https://onejira.atlassian.net/browse/MN-556)] - Some monitors doesn't have customizable no_data_timeframe +* [[MN-558](https://onejira.atlassian.net/browse/MN-558)] - AZure Application gateway monitoring healthy host check has no data +* [[MN-562](https://onejira.atlassian.net/browse/MN-562)] - Fix perpetual diff on no_data_timeframe + +## Improvement + +* [[MN-527](https://onejira.atlassian.net/browse/MN-527)] - Disable memory forecast monitor for gcp cloudsql +* [[MN-547](https://onejira.atlassian.net/browse/MN-547)] - Add monitor for MySQL lag and replication +* [[MN-559](https://onejira.atlassian.net/browse/MN-559)] - Remove awk hack and use terraform-docs 0.8.0 +* [[MN-561](https://onejira.atlassian.net/browse/MN-561)] - Add targetgroup in group by for ALB monitors + +## New Feature + +* [[MN-521](https://onejira.atlassian.net/browse/MN-521)] - Monitors for AWS ECS Fargate +* [[MN-554](https://onejira.atlassian.net/browse/MN-554)] - Monitors for K8S Velero +* [[MN-557](https://onejira.atlassian.net/browse/MN-557)] - SQL Server monitors +* [[MN-560](https://onejira.atlassian.net/browse/MN-560)] - Monitors for solr + +# v3.2.0 (December 13, 2019) + +## Bug + +* [[MN-512](https://onejira.atlassian.net/browse/MN-512)] - Elasticsearch latency is a counter +* [[MN-516](https://onejira.atlassian.net/browse/MN-516)] - ELB & ALB "no healthy instances" monitor's value is not accurate +* [[MN-518](https://onejira.atlassian.net/browse/MN-518)] - Respect best practice for message mention +* [[MN-523](https://onejira.atlassian.net/browse/MN-523)] - Fix Azure server farm status aggregator +* [[MN-524](https://onejira.atlassian.net/browse/MN-524)] - Azure virtual machine free space monitor has no data +* [[MN-526](https://onejira.atlassian.net/browse/MN-526)] - Fix wrong percentage calculation on GCP pubsub messages unavailable +* [[MN-530](https://onejira.atlassian.net/browse/MN-530)] - Fix RDS Replica Lag monitors name (use ms instead of %) +* [[MN-532](https://onejira.atlassian.net/browse/MN-532)] - Syntax warning on ignore_changes attribute +* [[MN-535](https://onejira.atlassian.net/browse/MN-535)] - Fix HCL2 syntax +* [[MN-544](https://onejira.atlassian.net/browse/MN-544)] - kubernetescluster tag does not exist anymore + +## Documentation + +* [[MN-519](https://onejira.atlassian.net/browse/MN-519)] - Opensource integrations and monitors + +## Epic + +* [[MN-62](https://onejira.atlassian.net/browse/MN-62)] - Monitors for AWS ECS + +## Improvement + +* [[MN-364](https://onejira.atlassian.net/browse/MN-364)] - Monitors for AWS NLB +* [[MN-509](https://onejira.atlassian.net/browse/MN-509)] - Fix monitor name for storage account monitor +* [[MN-510](https://onejira.atlassian.net/browse/MN-510)] - Fix metric for storage account queue monitor +* [[MN-513](https://onejira.atlassian.net/browse/MN-513)] - Fix false alarms on Azure storage monitoring +* [[MN-514](https://onejira.atlassian.net/browse/MN-514)] - Replace avg with min on ElasticSearch fetch latency +* [[MN-517](https://onejira.atlassian.net/browse/MN-517)] - Make warning threshold customizable on load balancer healthy instances monitors +* [[MN-531](https://onejira.atlassian.net/browse/MN-531)] - Add time aggregator on RDS Replica Lag Monitor +* [[MN-541](https://onejira.atlassian.net/browse/MN-541)] - Add notify_no_data parameter on every monitors where it is true +* [[MN-543](https://onejira.atlassian.net/browse/MN-543)] - alerting message could use common recovering conditional variable + +## New Feature + +* [[MN-182](https://onejira.atlassian.net/browse/MN-182)] - Monitors structure and config examples / stack template +* [[MN-366](https://onejira.atlassian.net/browse/MN-366)] - Monitors for Azure Application Gateway +* [[MN-525](https://onejira.atlassian.net/browse/MN-525)] - Monitors for AWS Beanstalk + +# v3.1.2 (September 09, 2019) + +## Improvement + +* [[MN-508](https://onejira.atlassian.net/browse/MN-508)] - GCP Pub/Sub Topic no data removal + +# v3.1.1 (September 06, 2019) + +## Improvement + +* [[MN-507](https://onejira.atlassian.net/browse/MN-507)] - add manifest for pubsub monitors + +# v3.1.0 (September 06, 2019) + +## Bug + +* [[MN-481](https://onejira.atlassian.net/browse/MN-481)] - Fix alb latency metric unit and homogenize latency thresholds + +## Documentation + +* [[MN-495](https://onejira.atlassian.net/browse/MN-495)] - Add requirements to kubernetes monitors readme + +## Improvement + +* [[MN-400](https://onejira.atlassian.net/browse/MN-400)] - GCP Pub Sub improvements +* [[MN-456](https://onejira.atlassian.net/browse/MN-456)] - remove as_count() on kubernetes_state.container.status_report.count.waiting +* [[MN-480](https://onejira.atlassian.net/browse/MN-480)] - Increase alert treshold for Stream Analytics streaming units utilization +* [[MN-482](https://onejira.atlassian.net/browse/MN-482)] - Ignore silenced since we now must use downtime instead +* [[MN-484](https://onejira.atlassian.net/browse/MN-484)] - Ajust monitor Hub Too many d2c telemetry ingress not sent +* [[MN-486](https://onejira.atlassian.net/browse/MN-486)] - Remove workaround for here doc fmt now it is fixed in terraform 0.12.6 +* [[MN-494](https://onejira.atlassian.net/browse/MN-494)] - Refactor auto update scripts +* [[MN-502](https://onejira.atlassian.net/browse/MN-502)] - Increase basic system triggers timeframes +* [[MN-504](https://onejira.atlassian.net/browse/MN-504)] - Update terraform and provider versions + +## New Feature + +* [[MN-39](https://onejira.atlassian.net/browse/MN-39)] - Monitors for Newrelic +* [[MN-413](https://onejira.atlassian.net/browse/MN-413)] - Terraform feature for pagerduty integration +* [[MN-455](https://onejira.atlassian.net/browse/MN-455)] - Monitor for kubernetes_state.container.status_report.count.terminated +* [[MN-46](https://onejira.atlassian.net/browse/MN-46)] - Monitors for AWS Lambdas +* [[MN-472](https://onejira.atlassian.net/browse/MN-472)] - Monitors for AWS SQS +* [[MN-485](https://onejira.atlassian.net/browse/MN-485)] - docker image for datadog terraform +* [[MN-487](https://onejira.atlassian.net/browse/MN-487)] - Datadog monitors VM integration RAM reserved +* [[MN-489](https://onejira.atlassian.net/browse/MN-489)] - Datadog monitors Azure VM Disk +* [[MN-490](https://onejira.atlassian.net/browse/MN-490)] - Changelog generation on git repos +* [[MN-492](https://onejira.atlassian.net/browse/MN-492)] - Indicate if a monitor is disabled by default on the README of each module +* [[MN-493](https://onejira.atlassian.net/browse/MN-493)] - Datadog monitors VM integration - requests failed +* [[MN-497](https://onejira.atlassian.net/browse/MN-497)] - Monitors for Docker +* [[MN-498](https://onejira.atlassian.net/browse/MN-498)] - Monitors for Kong +* [[MN-499](https://onejira.atlassian.net/browse/MN-499)] - Monitors HTTP, DNS and TLS + +# v3.0.0 (July 05, 2019) + +## Improvement + +* [[MN-476](https://onejira.atlassian.net/browse/MN-476)] - check and update sets with more than 1 notify no data +* [[MN-479](https://onejira.atlassian.net/browse/MN-479)] - Upgrade datadog terraform provider to v2 + +## Bug + +* [[MN-460](https://onejira.atlassian.net/browse/MN-460)] - Fix filter tags usage on keyvault and cosmos monitors +* [[MN-461](https://onejira.atlassian.net/browse/MN-461)] - Repair CI since it uses last 0.12 version image +* [[MN-477](https://onejira.atlassian.net/browse/MN-477)] - Fix wrong variable in query for kubernetes node inodes monitor +* [[MN-478](https://onejira.atlassian.net/browse/MN-478)] - Fix diff between CI and local env for sort command + +## Epic + +* [[MN-459](https://onejira.atlassian.net/browse/MN-459)] - Upgrade to terraform 0.12 (HCL 2.0) + +# v2.9.0 (May 09, 2019) + +## Improvement + +* [[MN-441](https://onejira.atlassian.net/browse/MN-441)] - support extra tags for custom filtering +* [[MN-446](https://onejira.atlassian.net/browse/MN-446)] - Monitor Azure SQL Elastic Pool + +## New Feature + +* [[MN-182](https://onejira.atlassian.net/browse/MN-182)] - Monitors structure and config examples / stack template +* [[MN-236](https://onejira.atlassian.net/browse/MN-236)] - Append optional custom field to name of monitor +* [[MN-453](https://onejira.atlassian.net/browse/MN-453)] - Monitors for kubernetes kubelet volume stats space and inodes + +## Bug + +* [[MN-442](https://onejira.atlassian.net/browse/MN-442)] - Do not notify nodata on node unschedulable monitor +* [[MN-444](https://onejira.atlassian.net/browse/MN-444)] - Kubernetes status_report count waiting should not trigger on containercreating +* [[MN-451](https://onejira.atlassian.net/browse/MN-451)] - Nodata alerts on Azure App Services downscale + +## Epic + +* [[MN-449](https://onejira.atlassian.net/browse/MN-449)] - Datadog global CI + +# v2.8.0 (April 23, 2019) + +## Improvement + +* [[MN-320](https://onejira.atlassian.net/browse/MN-320)] - Prefer greater operator logic +* [[MN-326](https://onejira.atlassian.net/browse/MN-326)] - use multi line query and EOQ everywhere +* [[MN-327](https://onejira.atlassian.net/browse/MN-327)] - Fix warning name for load balancer +* [[MN-328](https://onejira.atlassian.net/browse/MN-328)] - Improve mysql Innodb pool monitors +* [[MN-330](https://onejira.atlassian.net/browse/MN-330)] - Fix grouping and counter on azure monitors +* [[MN-331](https://onejira.atlassian.net/browse/MN-331)] - Improve mysql throughput monitor +* [[MN-429](https://onejira.atlassian.net/browse/MN-429)] - Update reference from cloudnative to pt-mon +* [[MN-437](https://onejira.atlassian.net/browse/MN-437)] - Update CI to use new gitlab runner + +## New Feature + +* [[MN-114](https://onejira.atlassian.net/browse/MN-114)] - Monitors for Kubernetes +* [[MN-390](https://onejira.atlassian.net/browse/MN-390)] - Monitors for Azure Functions + +## Bug + +* [[MN-360](https://onejira.atlassian.net/browse/MN-360)] - Feature enable/disable monitors creation does not work +* [[MN-415](https://onejira.atlassian.net/browse/MN-415)] - Remove Azure DBforMySQL Active connection query +* [[MN-430](https://onejira.atlassian.net/browse/MN-430)] - Use "instance" dimension on Azure App Service monitors metrics + +# v2.7.0 (April 05, 2019) + +## Improvement + +* [[MN-385](https://onejira.atlassian.net/browse/MN-385)] - Add Azure EventGrid Datadog monitors +* [[MN-417](https://onejira.atlassian.net/browse/MN-417)] - Monitors for Azure Virtual Machine +* [[MN-418](https://onejira.atlassian.net/browse/MN-418)] - Monitors for Azure Load Balancer + +## New Feature + +* [[MN-391](https://onejira.atlassian.net/browse/MN-391)] - Monitors for Azure Search +* [[MN-424](https://onejira.atlassian.net/browse/MN-424)] - Monitors for GCE instance + +## Bug + +* [[MN-405](https://onejira.atlassian.net/browse/MN-405)] - Fix Azure CosmosDb monitors due to metrics changes +* [[MN-425](https://onejira.atlassian.net/browse/MN-425)] - Fix App Services response time monitor + +# v2.6.0 (March 08, 2019) + +## Bug + +* [[MN-402](https://onejira.atlassian.net/browse/MN-402)] - Fix Azure DBforMySQL Active connection monitor +* [[MN-403](https://onejira.atlassian.net/browse/MN-403)] - Fix apache perpetual diff on apache connect monitor + +## Improvement + +* [[MN-392](https://onejira.atlassian.net/browse/MN-392)] - Update terraform-docs version in CI for DD monitors +* [[MN-397](https://onejira.atlassian.net/browse/MN-397)] - Exclude secretlist activity from Azure Key Vault latency monitor +* [[MN-404](https://onejira.atlassian.net/browse/MN-404)] - Make mysql Innodb buffer pool more tolerant + +# v2.5.1 (January 24, 2019) + +## Bug + +* [[MN-387](https://onejira.atlassian.net/browse/MN-387)] - Azure IotHub monitors triggers nodata alerts since 2.5.0 + +# v2.5.0 (January 23, 2019) + +## Bug + +* [[MN-335](https://onejira.atlassian.net/browse/MN-335)] - Fix successful monitors false alarms +* [[MN-383](https://onejira.atlassian.net/browse/MN-383)] - Remove Azure Monitors using compute_consumption_percent +* [[MN-386](https://onejira.atlassian.net/browse/MN-386)] - Caas Nginx Ingress monitor fix and update for VTS + +## Improvement + +* [[MN-237](https://onejira.atlassian.net/browse/MN-237)] - Add new Azure Monitors +* [[MN-295](https://onejira.atlassian.net/browse/MN-295)] - Remove Azure global feature +* [[MN-317](https://onejira.atlassian.net/browse/MN-317)] - Prefix all cloudprovider filter tag with +* [[MN-332](https://onejira.atlassian.net/browse/MN-332)] - Add filter_tags on IOTHub monitors +* [[MN-344](https://onejira.atlassian.net/browse/MN-344)] - add default to hit ratio monitors +* [[MN-377](https://onejira.atlassian.net/browse/MN-377)] - Monitor Azure SQL Server status with DD + +## New Feature + +* [[MN-336](https://onejira.atlassian.net/browse/MN-336)] - Convert bitbucket pipeline to gitlab ci + +# v2.4.0 (October 03, 2018) + +## Bug + +* [[MN-301](https://onejira.atlassian.net/browse/MN-301)] - Manage exclude on the module for filters +* [[MN-323](https://onejira.atlassian.net/browse/MN-323)] - fix pipeline using terraform-docs version 0.4.0 + +## Improvement + +* [[MN-309](https://onejira.atlassian.net/browse/MN-309)] - Improve monitors using as_count() and division + +## New Feature + +* [[MN-246](https://onejira.atlassian.net/browse/MN-246)] - Monitors for Azure MySQL +* [[MN-310](https://onejira.atlassian.net/browse/MN-310)] - Monitors for Azure Postgresql +* [[MN-316](https://onejira.atlassian.net/browse/MN-316)] - Monitors for Azure server farms + +# v2.3.1 (September 27, 2018) + +## Bug + +* [[MN-313](https://onejira.atlassian.net/browse/MN-313)] - elasticache memcached hit ratio miss multiplication by 100 + +## Improvement + +* [[MN-306](https://onejira.atlassian.net/browse/MN-306)] - Use system.load.norm.5 instead of system.load.5 +* [[MN-307](https://onejira.atlassian.net/browse/MN-307)] - GCP CloudSQL failover monitor increase timeframe +* [[MN-308](https://onejira.atlassian.net/browse/MN-308)] - Improve load balancer healthly host monitor +* [[MN-311](https://onejira.atlassian.net/browse/MN-311)] - Generate modules.tf with dynamic path +* [[MN-312](https://onejira.atlassian.net/browse/MN-312)] - Update readme with terraform-docs 0.4.0 +* [[MN-315](https://onejira.atlassian.net/browse/MN-315)] - Doc monitor / system / generic: free memory message + +# v2.3.0 (September 20, 2018) + +## Bug + +* [[MN-273](https://onejira.atlassian.net/browse/MN-273)] - service check query syntax does not work anymore +* [[MN-304](https://onejira.atlassian.net/browse/MN-304)] - Add default function to all latency based aws monitors + +## Improvement + +* [[MN-159](https://onejira.atlassian.net/browse/MN-159)] - Split delay variable in two separate variables (evaluation and new host) +* [[MN-162](https://onejira.atlassian.net/browse/MN-162)] - Add possibilty to disable / enable monitors +* [[MN-199](https://onejira.atlassian.net/browse/MN-199)] - Advanced monitors for Mongodb +* [[MN-275](https://onejira.atlassian.net/browse/MN-275)] - manage diff on monitor type from terraform +* [[MN-287](https://onejira.atlassian.net/browse/MN-287)] - Update service check monitors and doc +* [[MN-288](https://onejira.atlassian.net/browse/MN-288)] - Update all monitors with new tagging convention +* [[MN-293](https://onejira.atlassian.net/browse/MN-293)] - Optimize ci pipeline +* [[MN-294](https://onejira.atlassian.net/browse/MN-294)] - handle specific example for readme auto generation +* [[MN-300](https://onejira.atlassian.net/browse/MN-300)] - Improve and sandardize thresholds on GCP LB + +## New Feature + +* [[MN-32](https://onejira.atlassian.net/browse/MN-32)] - Monitors for AWS Elasticache +* [[MN-92](https://onejira.atlassian.net/browse/MN-92)] - Monitors for Mongodb +* [[MN-105](https://onejira.atlassian.net/browse/MN-105)] - Monitors for PostgreSQL +* [[MN-122](https://onejira.atlassian.net/browse/MN-122)] - Replication lag monitor for RDS +* [[MN-142](https://onejira.atlassian.net/browse/MN-142)] - Monitors for MySQL +* [[MN-224](https://onejira.atlassian.net/browse/MN-224)] - Monitors for GCP Cloud SQL +* [[MN-226](https://onejira.atlassian.net/browse/MN-226)] - Monitors for GCP PubSub +* [[MN-227](https://onejira.atlassian.net/browse/MN-227)] - Monitors for GCP LB +* [[MN-228](https://onejira.atlassian.net/browse/MN-228)] - Monitors for ElasticSearch +* [[MN-230](https://onejira.atlassian.net/browse/MN-230)] - Monitors for GCP BigQuery +* [[MN-247](https://onejira.atlassian.net/browse/MN-247)] - Monitors for Ark backups +* [[MN-248](https://onejira.atlassian.net/browse/MN-248)] - Monitors for Nginx Ingress Controller +* [[MN-271](https://onejira.atlassian.net/browse/MN-271)] - Monitors for Redis +* [[MN-281](https://onejira.atlassian.net/browse/MN-281)] - Monitor for disk forecast (system-generic) +* [[MN-284](https://onejira.atlassian.net/browse/MN-284)] - Add extra tags management to monitors +* [[MN-286](https://onejira.atlassian.net/browse/MN-286)] - Host Unreachable monitor on system generic +* [[MN-289](https://onejira.atlassian.net/browse/MN-289)] - Monitors for Nginx +* [[MN-290](https://onejira.atlassian.net/browse/MN-290)] - Monitors for Php-fpm + +# v2.2.1 (August 08, 2018) + +## Bug + +* [[MN-272](https://onejira.atlassian.net/browse/MN-272)] - php fpm has changed from port to ping_url for group by +* [[MN-276](https://onejira.atlassian.net/browse/MN-276)] - Fix ALB / ELB space aggregator + +# v2.2.0 (July 23, 2018) + +## Improvement + +* [[MN-259](https://onejira.atlassian.net/browse/MN-259)] - Improve readme generator + +## New Feature + +* [[MN-233](https://onejira.atlassian.net/browse/MN-233)] - Update main readme automatically +* [[MN-234](https://onejira.atlassian.net/browse/MN-234)] - Automatically generate output for each monitor + +# v2.1.1 (July 10, 2018) + +## Bug + +* [[MN-239](https://onejira.atlassian.net/browse/MN-239)] - Fix alb no healthy instances thresholds + +# v2.1.0 (June 29, 2018) + +## Bug + +* [[MN-168](https://onejira.atlassian.net/browse/MN-168)] - Apache can connect fails on query error + +## Improvement + +* [[MN-160](https://onejira.atlassian.net/browse/MN-160)] - Generalize the timeframe best practice +* [[MN-170](https://onejira.atlassian.net/browse/MN-170)] - Increase timeframe of ALB no healthy instances monitor +* [[MN-179](https://onejira.atlassian.net/browse/MN-179)] - No data events on Free disk inodes, Free disk space monitors +* [[MN-184](https://onejira.atlassian.net/browse/MN-184)] - no_data_timeframe should never be defined +* [[MN-185](https://onejira.atlassian.net/browse/MN-185)] - Monitors for Azure ServiceBus +* [[MN-197](https://onejira.atlassian.net/browse/MN-197)] - Ignore cache and buffer on memory monitor + +## New Feature + +* [[MN-191](https://onejira.atlassian.net/browse/MN-191)] - variabilize aggregator and timeframe when needed +* [[MN-231](https://onejira.atlassian.net/browse/MN-231)] - Update readme for every monitors sets easily + +## Documentation + +* [[MN-181](https://onejira.atlassian.net/browse/MN-181)] - update aws vpn readme to remove vpn_tunnel_address + +# v2.0.1 (April 02, 2018) + +## Bug + +* [[MN-166](https://onejira.atlassian.net/browse/MN-166)] - Fix apigateway latency notify on no data + +# v2.0.0 (March 25, 2018) + +## Bug + +* [[MN-81](https://onejira.atlassian.net/browse/MN-81)] - Fix basic monitors +* [[MN-88](https://onejira.atlassian.net/browse/MN-88)] - Treshold too high on aws_elb_latency +* [[MN-108](https://onejira.atlassian.net/browse/MN-108)] - typo monitor name apache middleware +* [[MN-113](https://onejira.atlassian.net/browse/MN-113)] - fix AWS ElasticSearch status monitor (aws.es.cluster_statusyellow) +* [[MN-121](https://onejira.atlassian.net/browse/MN-121)] - Fix ELB_backend_latency error +* [[MN-127](https://onejira.atlassian.net/browse/MN-127)] - Fix system tag in agent.yml +* [[MN-128](https://onejira.atlassian.net/browse/MN-128)] - [Datadog] Monitors for ELB issue with group by loadbalancer +* [[MN-139](https://onejira.atlassian.net/browse/MN-139)] - no data support for monitor name templating + +## Improvement + +* [[MN-66](https://onejira.atlassian.net/browse/MN-66)] - Refactor monitors repo with directories +* [[MN-96](https://onejira.atlassian.net/browse/MN-96)] - Update old monitors with new best practices +* [[MN-99](https://onejira.atlassian.net/browse/MN-99)] - Azure App Service monitor : count 2xx & 3xx http status codes as successful +* [[MN-102](https://onejira.atlassian.net/browse/MN-102)] - Auto-recovery for no-data tolerant monitors +* [[MN-124](https://onejira.atlassian.net/browse/MN-124)] - Add message input per monitor +* [[MN-134](https://onejira.atlassian.net/browse/MN-134)] - RAM alerts are now in non-business hours alerting by default. +* [[MN-135](https://onejira.atlassian.net/browse/MN-135)] - Use default on Event Hub query and update the used metrics +* [[MN-136](https://onejira.atlassian.net/browse/MN-136)] - Use rates for Azure IoT Hub monitors +* [[MN-137](https://onejira.atlassian.net/browse/MN-137)] - Use min as aggregate for Azure app services response time monitor +* [[MN-140](https://onejira.atlassian.net/browse/MN-140)] - Add a default function for api gateway, elb and alb monitors + +## New Feature + +* [[MN-48](https://onejira.atlassian.net/browse/MN-48)] - Monitors for API Gateway +* [[MN-49](https://onejira.atlassian.net/browse/MN-49)] - improve basic monitors +* [[MN-82](https://onejira.atlassian.net/browse/MN-82)] - Monitor message should be composed from variables +* [[MN-91](https://onejira.atlassian.net/browse/MN-91)] - Monitors for AWS VPN +* [[MN-107](https://onejira.atlassian.net/browse/MN-107)] - Monitors for AWS Elasticsearch Service +* [[MN-110](https://onejira.atlassian.net/browse/MN-110)] - Monitors for AWS Kinesis Firehose streams +* [[MN-112](https://onejira.atlassian.net/browse/MN-112)] - Monitors for AWS ALB + +## Sub-task + +* [[MN-30](https://onejira.atlassian.net/browse/MN-30)] - Monitors for AWS RDS +* [[MN-34](https://onejira.atlassian.net/browse/MN-34)] - Monitors for AWS ELB +* [[MN-74](https://onejira.atlassian.net/browse/MN-74)] - Azure App Services monitors +* [[MN-75](https://onejira.atlassian.net/browse/MN-75)] - Azure SQL monitors +* [[MN-76](https://onejira.atlassian.net/browse/MN-76)] - Azure Redis monitors +* [[MN-77](https://onejira.atlassian.net/browse/MN-77)] - Azure Event Hub monitors +* [[MN-78](https://onejira.atlassian.net/browse/MN-78)] - Azure Stream Analytics monitors +* [[MN-79](https://onejira.atlassian.net/browse/MN-79)] - Azure Storage monitors +* [[MN-80](https://onejira.atlassian.net/browse/MN-80)] - Azure IOT Hub monitors +* [[MN-90](https://onejira.atlassian.net/browse/MN-90)] - API Management monitors + +## Story + +* [[MN-73](https://onejira.atlassian.net/browse/MN-73)] - Azure managed services monitors + +## Documentation + +* [[MN-97](https://onejira.atlassian.net/browse/MN-97)] - Update readme on terraform monitors repo + +# v1.0.0 (December 24, 2017) + +## Improvement + +* [[MN-93](https://onejira.atlassian.net/browse/MN-93)] - AWS ELB custom tags +* [[MN-131](https://onejira.atlassian.net/browse/MN-131)] - Replace comparator variable by a hardcode comparator in monitor name +* [[MN-144](https://onejira.atlassian.net/browse/MN-144)] - Default nodata message must be 24x7 + +## New Feature + +* [[MN-43](https://onejira.atlassian.net/browse/MN-43)] - Agent installation + +## Story + +* [[MN-27](https://onejira.atlassian.net/browse/MN-27)] - Monitors for main middlewares diff --git a/.terraform/modules/datadog-monitors-system-generic/CONTRIBUTING.md b/.terraform/modules/datadog-monitors-system-generic/CONTRIBUTING.md new file mode 100755 index 0000000..8c1d90d --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/CONTRIBUTING.md @@ -0,0 +1,102 @@ +# Contributing + +When contributing to this repository, please first discuss the change you wish to make via issue, +email, or any other method with the owners of this repository before making a change. + +Please note we have a [code of conduct](#code-of-conduct), follow it in all your interactions with the project. + +## Considerations + +* If you have required permissions, you can create a branch from master else you can fork this repo to be able to submit a Pull Request. + +* [The changelog](CHANGELOG.md) is generated using issues IDs (Jira & Github) detected in commit messages which must follow `#GithubID My commit message` form. + +* If you would like to work on monitors you must follow our [templating best practices](TEMPLATING.md) to make this base homogenous and generic. + +* After any change, you will need to run the [auto update scripts](https://github.com/claranet/terraform-datadog-scripts/blob/master/README.md) to make sure all is up to date otherwise the CI pipeline will fail. + +## Pull Request Process + +1. Ensure to run the `auto_update.sh` script to be in an up to date and valid state. +2. Update the main README.md with details of changes to the interface, this includes new environment + variables, exposed ports, useful file locations and container parameters. +3. Increase the version numbers in any examples files and the README.md to the new version that this + Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). +4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you + do not have permission to do that, you may request the second reviewer to merge it for you. + +## Code of Conduct + +### Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +### Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +### Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +### Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +### Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at [FR-CloudPublic-github@fr.clara.net]. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +### Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ + diff --git a/.terraform/modules/datadog-monitors-system-generic/LICENSE b/.terraform/modules/datadog-monitors-system-generic/LICENSE new file mode 100755 index 0000000..6ad2829 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2018 Claranet + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/.terraform/modules/datadog-monitors-system-generic/NOTICE b/.terraform/modules/datadog-monitors-system-generic/NOTICE new file mode 100755 index 0000000..3238949 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/NOTICE @@ -0,0 +1,13 @@ +Copyright (c) 2018-2019 Claranet + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/.terraform/modules/datadog-monitors-system-generic/README.md b/.terraform/modules/datadog-monitors-system-generic/README.md new file mode 100755 index 0000000..b5bbbc6 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/README.md @@ -0,0 +1,243 @@ +# DataDog Monitors +[![Changelog](https://img.shields.io/badge/changelog-release-green.svg)](CHANGELOG.md) [![Notice](https://img.shields.io/badge/notice-copyright-yellow.svg)](NOTICE) [![Apache V2 License](http://img.shields.io/badge/license-Apache%20V2-blue.svg)](LICENSE) [![ ](https://git.fr.clara.net/claranet/pt-monitoring/projects/datadog/terraform/monitors/badges/master/pipeline.svg)](https://git.fr.clara.net/claranet/pt-monitoring/projects/datadog/terraform/monitors/commits/master) + +This repository aims to provide a base of generic and pre configured monitors for [Datadog](https://www.datadoghq.com/) templated thanks to [Terraform](https://www.terraform.io/) and the [Datadog Provider](https://github.com/terraform-providers/terraform-provider-datadog). + +## Important notes + +* This repository provide multiple Terraform modules which could be imported, you must choose the one(s) you need. +* Each of these modules contains the most commons monitors, but they probably do not fulfill all your needs. +* You still can create some specific DataDog monitors after importing a module, it's even advisable to complete your needs. +* You will find a complete `README.md` on each module, explaining how to use it and its specificities if there. +* The `alerting-message` module could be used to easily generate a templating message to re-use and could be used multiple times to suit different use cases. +* Some monitors are disabled by default because not generic or "plug and play" enough, if you use them you will need to tweak them or in some cases disabled another one which could "duplicate" the check. + +## Getting started + +### Versions + +Here are the minimum versions required to use these modules of integrations. + +```hcl +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} + +``` + +_Note_: if you want to use Datadog provider v2, you need to use version 3 of the modules in this repository. + +### DataDog provider + +Here is the last tester terraform provider version for datadog but next versions should work too. + +``` +provider "datadog" { + api_key = var.datadog_api_key + app_key = var.datadog_app_key +} + +``` + +Both of the `datadog_api_key` and `datadog_app_key` are unique to the each datadog account. You can define them in `terraform.tfvars` file: + +``` +datadog_api_key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +datadog_app_key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +``` + +### Variables + +Some variables need to be declared. + +``` +variable "environment" { + type = string + default = "dev" +} + +variable "datadog_api_key" { + type = string +} + +variable "datadog_app_key" { + type = string +} + +``` + +### Modules declaration example + +A quick example of alerting message module declaration: + +``` +locals { + oncall_24x7 = "@pagerduty-MyPagerService_NBH" + oncall_office_hours = "@pagerduty-MyPagerService_BH" +} + +module "datadog-message-alerting" { + source = "claranet/monitors/datadog//common/alerting-message" + version = "{revision}" + + message_alert = local.oncall_24x7 + message_warning = local.oncall_office_hours + message_nodata = local.oncall_24x7 +} + +module "datadog-message-alerting-bh-only" { + source = "claranet/monitors/datadog//common/alerting-message" + version = "{revision}" + + message_alert = local.oncall_office_hours + message_warning = local.oncall_office_hours + message_nodata = local.oncall_office_hours +} + +module "datadog-monitors-system-generic" { + source = "claranet/monitors/datadog//system/generic" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message + + memory_message = module.datadog-message-alerting-bh-only.alerting-message + # Use variables to customize monitors configuration +} + +# Other monitors modules to declare ... +#module "datadog-monitors-my-monitors-set" { +# source = "claranet/monitors/datadog//my/monitors/set" +# version = "{revision}" +# +# environment = var.environment +# message = module.datadog-message-alerting.alerting-message +#} + +``` + +* Replace `{revision}` to the last git tag available on this repository. +* The `//` is very important, it's a terraform specific syntax used to separate git url and folder path. +* `my/monitors/set` represents the path to a monitors set sub directory listed below. + +## Contributions + +Contributions are always welcome. + +The easiest way is to fork the repository, duplicate a module as "template" and work on it. + +An internal CI will run the `auto_update.sh` script to compare with proposed changes and check if everything is up to date. + +So, when PR is ready you will need to run this script and push its changes to pass the CI, see [scripts repository](https://github.com/claranet/terraform-datadog-scripts/) for more information. + +For example, this will regenerate every READMEs thanks to [terraform-docs](https://github.com/segmentio/terraform-docs) currently in v0.9.1. + +## Monitors summary + +- [caas](https://github.com/claranet/terraform-datadog-monitors/tree/master/caas/) + - [docker](https://github.com/claranet/terraform-datadog-monitors/tree/master/caas/docker/) + - [kubernetes](https://github.com/claranet/terraform-datadog-monitors/tree/master/caas/kubernetes/) + - [ark](https://github.com/claranet/terraform-datadog-monitors/tree/master/caas/kubernetes/ark/) + - [cluster](https://github.com/claranet/terraform-datadog-monitors/tree/master/caas/kubernetes/cluster/) + - [ingress](https://github.com/claranet/terraform-datadog-monitors/tree/master/caas/kubernetes/ingress/) + - [vts](https://github.com/claranet/terraform-datadog-monitors/tree/master/caas/kubernetes/ingress/vts/) + - [node](https://github.com/claranet/terraform-datadog-monitors/tree/master/caas/kubernetes/node/) + - [pod](https://github.com/claranet/terraform-datadog-monitors/tree/master/caas/kubernetes/pod/) + - [velero](https://github.com/claranet/terraform-datadog-monitors/tree/master/caas/kubernetes/velero/) + - [workload](https://github.com/claranet/terraform-datadog-monitors/tree/master/caas/kubernetes/workload/) +- [cloud](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/) + - [aws](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/) + - [alb](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/alb/) + - [apigateway](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/apigateway/) + - [beanstalk](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/beanstalk/) + - [ecs](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/ecs/) + - [common](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/ecs/common/) + - [ec2-cluster](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/ecs/ec2-cluster/) + - [fargate](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/ecs/fargate/) + - [elasticache](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/elasticache/) + - [common](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/elasticache/common/) + - [memcached](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/elasticache/memcached/) + - [redis](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/elasticache/redis/) + - [elasticsearch](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/elasticsearch/) + - [elb](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/elb/) + - [kinesis-firehose](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/kinesis-firehose/) + - [lambda](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/lambda/) + - [nlb](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/nlb/) + - [rds](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/rds/) + - [aurora](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/rds/aurora/) + - [mysql](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/rds/aurora/mysql/) + - [postgresql](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/rds/aurora/postgresql/) + - [common](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/rds/common/) + - [sqs](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/sqs/) + - [vpn](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/aws/vpn/) + - [azure](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/) + - [apimanagement](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/apimanagement/) + - [app-gateway](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/app-gateway/) + - [app-services](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/app-services/) + - [azure-search](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/azure-search/) + - [cosmosdb](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/cosmosdb/) + - [datalakestore](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/datalakestore/) + - [eventgrid](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/eventgrid/) + - [eventhub](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/eventhub/) + - [functions](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/functions/) + - [iothubs](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/iothubs/) + - [keyvault](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/keyvault/) + - [load-balancer](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/load-balancer/) + - [mysql](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/mysql/) + - [postgresql](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/postgresql/) + - [redis](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/redis/) + - [serverfarms](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/serverfarms/) + - [servicebus](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/servicebus/) + - [sql-database](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/sql-database/) + - [sql-elasticpool](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/sql-elasticpool/) + - [storage](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/storage/) + - [stream-analytics](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/stream-analytics/) + - [virtual-machine](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/azure/virtual-machine/) + - [gcp](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/) + - [big-query](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/big-query/) + - [cloud-sql](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/cloud-sql/) + - [common](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/cloud-sql/common/) + - [mysql](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/cloud-sql/mysql/) + - [gce](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/gce/) + - [instance](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/gce/instance/) + - [lb](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/lb/) + - [memorystore](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/memorystore/) + - [redis](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/memorystore/redis/) + - [pubsub](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/pubsub/) + - [subscription](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/pubsub/subscription/) + - [topic](https://github.com/claranet/terraform-datadog-monitors/tree/master/cloud/gcp/pubsub/topic/) +- [common](https://github.com/claranet/terraform-datadog-monitors/tree/master/common/) + - [alerting-message](https://github.com/claranet/terraform-datadog-monitors/tree/master/common/alerting-message/) + - [filter-tags](https://github.com/claranet/terraform-datadog-monitors/tree/master/common/filter-tags/) +- [database](https://github.com/claranet/terraform-datadog-monitors/tree/master/database/) + - [elasticsearch](https://github.com/claranet/terraform-datadog-monitors/tree/master/database/elasticsearch/) + - [mongodb](https://github.com/claranet/terraform-datadog-monitors/tree/master/database/mongodb/) + - [mysql](https://github.com/claranet/terraform-datadog-monitors/tree/master/database/mysql/) + - [postgresql](https://github.com/claranet/terraform-datadog-monitors/tree/master/database/postgresql/) + - [proxysql](https://github.com/claranet/terraform-datadog-monitors/tree/master/database/proxysql/) + - [redis](https://github.com/claranet/terraform-datadog-monitors/tree/master/database/redis/) + - [solr](https://github.com/claranet/terraform-datadog-monitors/tree/master/database/solr/) + - [sqlserver](https://github.com/claranet/terraform-datadog-monitors/tree/master/database/sqlserver/) + - [zookeeper](https://github.com/claranet/terraform-datadog-monitors/tree/master/database/zookeeper/) +- [middleware](https://github.com/claranet/terraform-datadog-monitors/tree/master/middleware/) + - [apache](https://github.com/claranet/terraform-datadog-monitors/tree/master/middleware/apache/) + - [kong](https://github.com/claranet/terraform-datadog-monitors/tree/master/middleware/kong/) + - [nginx](https://github.com/claranet/terraform-datadog-monitors/tree/master/middleware/nginx/) + - [php-fpm](https://github.com/claranet/terraform-datadog-monitors/tree/master/middleware/php-fpm/) +- [network](https://github.com/claranet/terraform-datadog-monitors/tree/master/network/) + - [dns](https://github.com/claranet/terraform-datadog-monitors/tree/master/network/dns/) + - [http](https://github.com/claranet/terraform-datadog-monitors/tree/master/network/http/) + - [ssl](https://github.com/claranet/terraform-datadog-monitors/tree/master/network/http/ssl/) + - [webcheck](https://github.com/claranet/terraform-datadog-monitors/tree/master/network/http/webcheck/) + - [tls](https://github.com/claranet/terraform-datadog-monitors/tree/master/network/tls/) +- [saas](https://github.com/claranet/terraform-datadog-monitors/tree/master/saas/) + - [new-relic](https://github.com/claranet/terraform-datadog-monitors/tree/master/saas/new-relic/) +- [system](https://github.com/claranet/terraform-datadog-monitors/tree/master/system/) + - [generic](https://github.com/claranet/terraform-datadog-monitors/tree/master/system/generic/) + - [unreachable](https://github.com/claranet/terraform-datadog-monitors/tree/master/system/unreachable/) diff --git a/.terraform/modules/datadog-monitors-system-generic/TEMPLATING.md b/.terraform/modules/datadog-monitors-system-generic/TEMPLATING.md new file mode 100755 index 0000000..ce4138d --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/TEMPLATING.md @@ -0,0 +1,10 @@ +# Templating + +This documentation aims to help contributors to build their monitors: +* working with datadog and using some tips or advices. +* respect guideline to keep this base generic and usable for everybody. +* preserve homogeneity over every modules provided on this repository. + +## TODO + +To migrate from confluence diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/docker/README.md b/.terraform/modules/datadog-monitors-system-generic/caas/docker/README.md new file mode 100755 index 0000000..6916623 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/docker/README.md @@ -0,0 +1,83 @@ +# CAAS DOCKER DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-caas-docker" { + source = "claranet/monitors/datadog//caas/docker" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Docker Container Memory Used (disabled by default) +- Docker does not respond + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.memory_used](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.not_responding](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [memory\_used\_enabled](#input\_memory\_used\_enabled) | Flag to enable Container Memory Usage monitor | `string` | `"false"` | no | +| [memory\_used\_extra\_tags](#input\_memory\_used\_extra\_tags) | Extra tags for Container Memory Usage monitor | `list(string)` | `[]` | no | +| [memory\_used\_message](#input\_memory\_used\_message) | Custom message for the Container Memory Usage monitor | `string` | `""` | no | +| [memory\_used\_threshold\_critical](#input\_memory\_used\_threshold\_critical) | Container Memory Usage critical threshold | `string` | `90` | no | +| [memory\_used\_threshold\_warning](#input\_memory\_used\_threshold\_warning) | Container Memory Usage warning threshold | `string` | `85` | no | +| [memory\_used\_time\_aggregator](#input\_memory\_used\_time\_aggregator) | Time aggregator for the Container Memory Usage monitor | `string` | `"min"` | no | +| [memory\_used\_timeframe](#input\_memory\_used\_timeframe) | Timeframe for the Container Memory Usage monitor | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [not\_responding\_enabled](#input\_not\_responding\_enabled) | Flag to enable Docker does not respond monitor | `string` | `"true"` | no | +| [not\_responding\_extra\_tags](#input\_not\_responding\_extra\_tags) | Extra tags for Docker does not respond monitor | `list(string)` | `[]` | no | +| [not\_responding\_message](#input\_not\_responding\_message) | Custom message for Docker does not respond monitor | `string` | `""` | no | +| [not\_responding\_no\_data\_timeframe](#input\_not\_responding\_no\_data\_timeframe) | Docker does not respond monitor no data timeframe | `string` | `10` | no | +| [not\_responding\_threshold\_warning](#input\_not\_responding\_threshold\_warning) | Docker does not respond monitor (warning threshold) | `string` | `3` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [memory\_used\_id](#output\_memory\_used\_id) | id for monitor memory\_used | +| [not\_responding\_id](#output\_not\_responding\_id) | id for monitor not\_responding | +## Related documentation + +* [Datadog Docker integration](https://docs.datadoghq.com/integrations/docker_daemon/) diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/docker/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/caas/docker/inputs.tf new file mode 100755 index 0000000..9fdbb7e --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/docker/inputs.tf @@ -0,0 +1,123 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# +# Not Responding +# +variable "not_responding_enabled" { + description = "Flag to enable Docker does not respond monitor" + type = string + default = "true" +} + +variable "not_responding_message" { + description = "Custom message for Docker does not respond monitor" + type = string + default = "" +} + +variable "not_responding_threshold_warning" { + description = "Docker does not respond monitor (warning threshold)" + type = string + default = 3 +} + +variable "not_responding_no_data_timeframe" { + description = "Docker does not respond monitor no data timeframe" + type = string + default = 10 +} + +variable "not_responding_extra_tags" { + description = "Extra tags for Docker does not respond monitor" + type = list(string) + default = [] +} + +# +# Container Memory Usage +# +variable "memory_used_enabled" { + description = "Flag to enable Container Memory Usage monitor" + type = string + default = "false" +} + +variable "memory_used_message" { + description = "Custom message for the Container Memory Usage monitor" + type = string + default = "" +} + +variable "memory_used_time_aggregator" { + description = "Time aggregator for the Container Memory Usage monitor" + type = string + default = "min" +} + +variable "memory_used_timeframe" { + description = "Timeframe for the Container Memory Usage monitor" + type = string + default = "last_5m" +} + +variable "memory_used_threshold_warning" { + description = "Container Memory Usage warning threshold" + type = string + default = 85 +} + +variable "memory_used_threshold_critical" { + description = "Container Memory Usage critical threshold" + type = string + default = 90 +} + +variable "memory_used_extra_tags" { + description = "Extra tags for Container Memory Usage monitor" + type = list(string) + default = [] +} diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/docker/modules.tf b/.terraform/modules/datadog-monitors-system-generic/caas/docker/modules.tf new file mode 100755 index 0000000..4038380 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/docker/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "docker" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/docker/monitors-docker.tf b/.terraform/modules/datadog-monitors-system-generic/caas/docker/monitors-docker.tf new file mode 100755 index 0000000..690b42b --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/docker/monitors-docker.tf @@ -0,0 +1,61 @@ +# +# Service Check +# +resource "datadog_monitor" "not_responding" { + count = var.not_responding_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Docker does not respond" + message = coalesce(var.not_responding_message, var.message) + type = "service check" + + query = < ${var.memory_used_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.memory_used_threshold_warning + critical = var.memory_used_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:docker", "provider:docker", "resource:docker", "team:claranet", "created-by:terraform"], var.memory_used_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/docker/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/caas/docker/outputs.tf new file mode 100755 index 0000000..1fcd1b0 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/docker/outputs.tf @@ -0,0 +1,10 @@ +output "memory_used_id" { + description = "id for monitor memory_used" + value = datadog_monitor.memory_used.*.id +} + +output "not_responding_id" { + description = "id for monitor not_responding" + value = datadog_monitor.not_responding.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/docker/versions.tf b/.terraform/modules/datadog-monitors-system-generic/caas/docker/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/docker/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ark/README.md b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ark/README.md new file mode 100755 index 0000000..d981b7d --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ark/README.md @@ -0,0 +1,107 @@ +# CAAS KUBERNETES ARK DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-caas-kubernetes-ark" { + source = "claranet/monitors/datadog//caas/kubernetes/ark" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Ark backup failed + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.ark_schedules_monitor](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [ark\_schedules\_enabled](#input\_ark\_schedules\_enabled) | Flag to enable Ark schedules monitor | `string` | `"true"` | no | +| [ark\_schedules\_extra\_tags](#input\_ark\_schedules\_extra\_tags) | Extra tags for Ark schedules monitor | `list(string)` | `[]` | no | +| [ark\_schedules\_monitor\_message](#input\_ark\_schedules\_monitor\_message) | Custom message for Ark schedules monitor | `string` | `""` | no | +| [ark\_schedules\_monitor\_no\_data\_timeframe](#input\_ark\_schedules\_monitor\_no\_data\_timeframe) | No data timeframe in minutes | `number` | `2880` | no | +| [ark\_schedules\_monitor\_timeframe](#input\_ark\_schedules\_monitor\_timeframe) | Monitor timeframe for Ark schedules monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1d"` | no | +| [environment](#input\_environment) | Architecture environment | `any` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [ark\_schedules\_monitor\_id](#output\_ark\_schedules\_monitor\_id) | id for monitor ark\_schedules\_monitor | +## Related documentation + +DataDog blog: https://www.datadoghq.com/blog/monitor-prometheus-metrics +Heptio Ark minimum release: https://github.com/heptio/ark/releases/tag/v0.9.0 + +## Ark annotations for Datadog + +``` +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + namespace: heptio-ark + name: ark +spec: + replicas: 1 + template: + metadata: + labels: + component: ark + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "8085" + prometheus.io/path: "/metrics" + ad.datadoghq.com/ark.check_names: |- + ["prometheus"] + ad.datadoghq.com/ark.init_configs: |- + [{}] + ad.datadoghq.com/ark.instances: |- + [ + { + "prometheus_url": "http://%%host%%:8085/metrics", + "namespace": "ark", + "metrics": ["ark_backup_*"], + "tags": ["dd_monitoring:enabled","dd_ark:enabled","env:prod"] + } + ] +``` diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ark/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ark/inputs.tf new file mode 100755 index 0000000..50f3560 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ark/inputs.tf @@ -0,0 +1,76 @@ +# Datadog global variables + +variable "environment" { + description = "Architecture environment" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# Datadog monitors variables + +variable "ark_schedules_monitor_message" { + description = "Custom message for Ark schedules monitor" + type = string + default = "" +} + +variable "ark_schedules_monitor_timeframe" { + description = "Monitor timeframe for Ark schedules monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1d" +} + +variable "ark_schedules_enabled" { + description = "Flag to enable Ark schedules monitor" + type = string + default = "true" +} + +variable "ark_schedules_extra_tags" { + description = "Extra tags for Ark schedules monitor" + type = list(string) + default = [] +} + +variable "ark_schedules_monitor_no_data_timeframe" { + description = "No data timeframe in minutes" + default = 2880 +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ark/modules.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ark/modules.tf new file mode 100755 index 0000000..d3f43ff --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ark/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "ark" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ark/monitors-ark.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ark/monitors-ark.tf new file mode 100755 index 0000000..d41b417 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ark/monitors-ark.tf @@ -0,0 +1,30 @@ +resource "datadog_monitor" "ark_schedules_monitor" { + count = var.ark_schedules_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Ark backup failed" + type = "query alert" + message = coalesce(var.ark_schedules_monitor_message, var.message) + + query = < 1 +EOQ + + monitor_thresholds { + critical = 1 + warning = 0 + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + no_data_timeframe = var.ark_schedules_monitor_no_data_timeframe + + notify_no_data = var.notify_no_data + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:caas", "provider:prometheus", "resource:ark", "team:claranet", "created-by:terraform"], var.ark_schedules_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ark/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ark/outputs.tf new file mode 100755 index 0000000..1c588cd --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ark/outputs.tf @@ -0,0 +1,5 @@ +output "ark_schedules_monitor_id" { + description = "id for monitor ark_schedules_monitor" + value = datadog_monitor.ark_schedules_monitor.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ark/versions.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ark/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ark/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/cluster/README.md b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/cluster/README.md new file mode 100755 index 0000000..9f14cbd --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/cluster/README.md @@ -0,0 +1,79 @@ +# CAAS KUBERNETES CLUSTER DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-caas-kubernetes-cluster" { + source = "claranet/monitors/datadog//caas/kubernetes/cluster" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Kubernetes API server does not respond + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.apiserver](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [apiserver\_enabled](#input\_apiserver\_enabled) | Flag to enable API server monitor | `string` | `"true"` | no | +| [apiserver\_extra\_tags](#input\_apiserver\_extra\_tags) | Extra tags for API server monitor | `list(string)` | `[]` | no | +| [apiserver\_message](#input\_apiserver\_message) | Custom message for API server monitor | `string` | `""` | no | +| [apiserver\_no\_data\_timeframe](#input\_apiserver\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [apiserver\_threshold\_warning](#input\_apiserver\_threshold\_warning) | API server monitor (warning threshold) | `string` | `3` | no | +| [environment](#input\_environment) | Architecture environment | `any` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [apiserver\_id](#output\_apiserver\_id) | id for monitor apiserver | +## Related documentation + +* [Datadog metrics](https://docs.datadoghq.com/agent/kubernetes/metrics/) +* [Datadog documentation](https://docs.datadoghq.com/integrations/kubernetes/) +* [Datadog Blog](https://www.datadoghq.com/blog/monitor-kubernetes-docker/) + +## Requirements + +* Datadog Agent > v6.6 diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/cluster/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/cluster/inputs.tf new file mode 100755 index 0000000..248b1f9 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/cluster/inputs.tf @@ -0,0 +1,77 @@ +# Datadog global variables + +variable "environment" { + description = "Architecture environment" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "apiserver_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# Datadog monitors variables + +variable "apiserver_enabled" { + description = "Flag to enable API server monitor" + type = string + default = "true" +} + +variable "apiserver_extra_tags" { + description = "Extra tags for API server monitor" + type = list(string) + default = [] +} + +variable "apiserver_message" { + description = "Custom message for API server monitor" + type = string + default = "" +} + +variable "apiserver_threshold_warning" { + description = "API server monitor (warning threshold)" + type = string + default = 3 +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/cluster/modules.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/cluster/modules.tf new file mode 100755 index 0000000..a57cf43 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/cluster/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "kubernetes" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/cluster/monitors-k8s-cluster.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/cluster/monitors-k8s-cluster.tf new file mode 100755 index 0000000..6219dc3 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/cluster/monitors-k8s-cluster.tf @@ -0,0 +1,29 @@ +resource "datadog_monitor" "apiserver" { + count = var.apiserver_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Kubernetes API server does not respond" + message = coalesce(var.apiserver_message, var.message) + + type = "service check" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../../common/filter-tags | n/a | +| [filter-tags-4xx](#module\_filter-tags-4xx) | ../../../../common/filter-tags | n/a | +| [filter-tags-5xx](#module\_filter-tags-5xx) | ../../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.nginx_ingress_too_many_4xx](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.nginx_ingress_too_many_5xx](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [artificial\_requests\_count](#input\_artificial\_requests\_count) | Number of false requests used to mitigate false positive in case of low trafic | `number` | `5` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [ingress\_4xx\_enabled](#input\_ingress\_4xx\_enabled) | Flag to enable Ingress 4xx errors monitor | `string` | `"true"` | no | +| [ingress\_4xx\_extra\_tags](#input\_ingress\_4xx\_extra\_tags) | Extra tags for Ingress 4xx errors monitor | `list(string)` | `[]` | no | +| [ingress\_4xx\_message](#input\_ingress\_4xx\_message) | Message sent when an alert is triggered | `string` | `""` | no | +| [ingress\_4xx\_threshold\_critical](#input\_ingress\_4xx\_threshold\_critical) | 4xx critical threshold in percentage | `string` | `"40"` | no | +| [ingress\_4xx\_threshold\_warning](#input\_ingress\_4xx\_threshold\_warning) | 4xx warning threshold in percentage | `string` | `"20"` | no | +| [ingress\_4xx\_time\_aggregator](#input\_ingress\_4xx\_time\_aggregator) | Monitor aggregator for Ingress 4xx errors [available values: min, max or avg] | `string` | `"min"` | no | +| [ingress\_4xx\_timeframe](#input\_ingress\_4xx\_timeframe) | Monitor timeframe for Ingress 4xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [ingress\_5xx\_enabled](#input\_ingress\_5xx\_enabled) | Flag to enable Ingress 5xx errors monitor | `string` | `"true"` | no | +| [ingress\_5xx\_extra\_tags](#input\_ingress\_5xx\_extra\_tags) | Extra tags for Ingress 5xx errors monitor | `list(string)` | `[]` | no | +| [ingress\_5xx\_message](#input\_ingress\_5xx\_message) | Message sent when an alert is triggered | `string` | `""` | no | +| [ingress\_5xx\_threshold\_critical](#input\_ingress\_5xx\_threshold\_critical) | 5xx critical threshold in percentage | `string` | `"20"` | no | +| [ingress\_5xx\_threshold\_warning](#input\_ingress\_5xx\_threshold\_warning) | 5xx warning threshold in percentage | `string` | `"10"` | no | +| [ingress\_5xx\_time\_aggregator](#input\_ingress\_5xx\_time\_aggregator) | Monitor aggregator for Ingress 5xx errors [available values: min, max or avg] | `string` | `"min"` | no | +| [ingress\_5xx\_timeframe](#input\_ingress\_5xx\_timeframe) | Monitor timeframe for Ingress 5xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [nginx\_ingress\_too\_many\_4xx\_id](#output\_nginx\_ingress\_too\_many\_4xx\_id) | id for monitor nginx\_ingress\_too\_many\_4xx | +| [nginx\_ingress\_too\_many\_5xx\_id](#output\_nginx\_ingress\_too\_many\_5xx\_id) | id for monitor nginx\_ingress\_too\_many\_5xx | +## Related documentation + +DataDog blog: https://www.datadoghq.com/blog/monitor-prometheus-metrics +https://github.com/kubernetes/ingress-nginx/pull/423/commits/1d38e3a38425f08de2f75fcae13896a3fec4d144 + +## Nginx Ingress Controller setup + +This configuration and monitors only work for ingress controller version : +- \>= 0.10 because ingress is beta before that and metrics naming convention not stable +- <= 0.15 because ingress does not use VTS metrics since 0.16 +Enable the following flags in the Nginx Ingress Controller chart +controller.stats.enabled=true,controller.metrics.enabled=true +and the following Datadog agent configuration for each ingress controller: +``` +datadog: + confd: + prometheus.yaml: |- + #nginx_upstream_responses_total{ingress_class,namespace,server,status_code:{1xx,2xx,3xx,4xx,5xx},upstream} + #nginx_upstream_requests_total{ingress_class,namespace,server,upstream} + init_config: + instances: + # The prometheus endpoint to query from + - prometheus_url: http://nginx-ingress-controller-metrics:9913/metrics + # This is NOT the ingress namespace, it is the prefix that will be used for the custom metrics + namespace: nginx-ingress + # Filter on the following metrics only + metrics: + - "nginx_upstream_requests_total" + - "nginx_upstream_responses_total" + # Adapt the tags to the current convention and verify that the monitor will match + tags: + - dd_monitoring:enabled + - dd_ingress:enabled + - dd_ingress_class:nginx + - env:ENV +``` diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ingress/vts/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ingress/vts/inputs.tf new file mode 100755 index 0000000..d8820d2 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ingress/vts/inputs.tf @@ -0,0 +1,135 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +#Ingress + +variable "ingress_5xx_enabled" { + description = "Flag to enable Ingress 5xx errors monitor" + type = string + default = "true" +} + +variable "ingress_5xx_extra_tags" { + description = "Extra tags for Ingress 5xx errors monitor" + type = list(string) + default = [] +} + +variable "ingress_5xx_message" { + description = "Message sent when an alert is triggered" + default = "" +} + +variable "ingress_5xx_time_aggregator" { + description = "Monitor aggregator for Ingress 5xx errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "ingress_5xx_timeframe" { + description = "Monitor timeframe for Ingress 5xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "ingress_5xx_threshold_critical" { + type = string + default = "20" + description = "5xx critical threshold in percentage" +} + +variable "ingress_5xx_threshold_warning" { + type = string + default = "10" + description = "5xx warning threshold in percentage" +} + +variable "ingress_4xx_enabled" { + description = "Flag to enable Ingress 4xx errors monitor" + type = string + default = "true" +} + +variable "ingress_4xx_extra_tags" { + description = "Extra tags for Ingress 4xx errors monitor" + type = list(string) + default = [] +} + +variable "ingress_4xx_message" { + description = "Message sent when an alert is triggered" + default = "" +} + +variable "ingress_4xx_time_aggregator" { + description = "Monitor aggregator for Ingress 4xx errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "ingress_4xx_timeframe" { + description = "Monitor timeframe for Ingress 4xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "ingress_4xx_threshold_critical" { + type = string + default = "40" + description = "4xx critical threshold in percentage" +} + +variable "ingress_4xx_threshold_warning" { + type = string + default = "20" + description = "4xx warning threshold in percentage" +} + +variable "artificial_requests_count" { + default = 5 + description = "Number of false requests used to mitigate false positive in case of low trafic" +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ingress/vts/modules.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ingress/vts/modules.tf new file mode 100755 index 0000000..1ce323a --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ingress/vts/modules.tf @@ -0,0 +1,35 @@ +module "filter-tags" { + source = "../../../../common/filter-tags" + + environment = var.environment + resource = "ingress" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags_excluded = ["upstream:upstream-default-backend"] +} + +module "filter-tags-5xx" { + source = "../../../../common/filter-tags" + + environment = var.environment + resource = "ingress" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["status_code:5xx"] + extra_tags_excluded = ["upstream:upstream-default-backend"] +} + +module "filter-tags-4xx" { + source = "../../../../common/filter-tags" + + environment = var.environment + resource = "ingress" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["status_code:4xx"] + extra_tags_excluded = ["upstream:upstream-default-backend"] +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ingress/vts/monitors-ingress.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ingress/vts/monitors-ingress.tf new file mode 100755 index 0000000..4ced3e7 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ingress/vts/monitors-ingress.tf @@ -0,0 +1,62 @@ +resource "datadog_monitor" "nginx_ingress_too_many_5xx" { + count = var.ingress_5xx_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Nginx Ingress 5xx errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.ingress_5xx_message, var.message) + type = "query alert" + + query = < ${var.ingress_5xx_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.ingress_5xx_threshold_warning + critical = var.ingress_5xx_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:prometheus", "resource:nginx-ingress-controller", "team:claranet", "created-by:terraform"], var.ingress_5xx_extra_tags) +} + +resource "datadog_monitor" "nginx_ingress_too_many_4xx" { + count = var.ingress_4xx_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Nginx Ingress 4xx errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.ingress_4xx_message, var.message) + type = "query alert" + + query = < ${var.ingress_4xx_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.ingress_4xx_threshold_warning + critical = var.ingress_4xx_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:prometheus", "resource:nginx-ingress-controller", "team:claranet", "created-by:terraform"], var.ingress_4xx_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ingress/vts/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ingress/vts/outputs.tf new file mode 100755 index 0000000..52bde5a --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ingress/vts/outputs.tf @@ -0,0 +1,10 @@ +output "nginx_ingress_too_many_4xx_id" { + description = "id for monitor nginx_ingress_too_many_4xx" + value = datadog_monitor.nginx_ingress_too_many_4xx.*.id +} + +output "nginx_ingress_too_many_5xx_id" { + description = "id for monitor nginx_ingress_too_many_5xx" + value = datadog_monitor.nginx_ingress_too_many_5xx.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ingress/vts/versions.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ingress/vts/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/ingress/vts/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/node/README.md b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/node/README.md new file mode 100755 index 0000000..8dc15bd --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/node/README.md @@ -0,0 +1,152 @@ +# CAAS KUBERNETES NODE DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-caas-kubernetes-node" { + source = "claranet/monitors/datadog//caas/kubernetes/node" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Kubernetes Node Disk pressure +- Kubernetes Node Frequent unregister net device +- Kubernetes Node Kubelet API does not respond +- Kubernetes Node Kubelet sync loop that updates containers does not work +- Kubernetes Node Memory pressure +- Kubernetes Node not ready +- Kubernetes Node Out of disk +- Kubernetes Node unschedulable +- Kubernetes Node volume inodes usage +- Kubernetes Node volume space usage + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | +| [filter-tags-unschedulable](#module\_filter-tags-unschedulable) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.disk_out](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.disk_pressure](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.kubelet_ping](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.kubelet_syncloop](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.memory_pressure](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.node_unschedulable](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ready](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.unregister_net_device](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.volume_inodes](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.volume_space](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [disk\_out\_enabled](#input\_disk\_out\_enabled) | Flag to enable Out of disk monitor | `string` | `"true"` | no | +| [disk\_out\_extra\_tags](#input\_disk\_out\_extra\_tags) | Extra tags for Out of disk monitor | `list(string)` | `[]` | no | +| [disk\_out\_message](#input\_disk\_out\_message) | Custom message for Out of disk monitor | `string` | `""` | no | +| [disk\_out\_threshold\_warning](#input\_disk\_out\_threshold\_warning) | Out of disk monitor (warning threshold) | `string` | `3` | no | +| [disk\_pressure\_enabled](#input\_disk\_pressure\_enabled) | Flag to enable Disk pressure monitor | `string` | `"true"` | no | +| [disk\_pressure\_extra\_tags](#input\_disk\_pressure\_extra\_tags) | Extra tags for Disk pressure monitor | `list(string)` | `[]` | no | +| [disk\_pressure\_message](#input\_disk\_pressure\_message) | Custom message for Disk pressure monitor | `string` | `""` | no | +| [disk\_pressure\_threshold\_warning](#input\_disk\_pressure\_threshold\_warning) | Disk pressure monitor (warning threshold) | `string` | `3` | no | +| [environment](#input\_environment) | Architecture environment | `any` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [kubelet\_ping\_enabled](#input\_kubelet\_ping\_enabled) | Flag to enable Kubelet ping monitor | `string` | `"true"` | no | +| [kubelet\_ping\_extra\_tags](#input\_kubelet\_ping\_extra\_tags) | Extra tags for Kubelet ping monitor | `list(string)` | `[]` | no | +| [kubelet\_ping\_message](#input\_kubelet\_ping\_message) | Custom message for Kubelet ping monitor | `string` | `""` | no | +| [kubelet\_ping\_no\_data\_timeframe](#input\_kubelet\_ping\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [kubelet\_ping\_threshold\_warning](#input\_kubelet\_ping\_threshold\_warning) | Kubelet ping monitor (warning threshold) | `string` | `3` | no | +| [kubelet\_syncloop\_enabled](#input\_kubelet\_syncloop\_enabled) | Flag to enable Kubelet sync loop monitor | `string` | `"true"` | no | +| [kubelet\_syncloop\_extra\_tags](#input\_kubelet\_syncloop\_extra\_tags) | Extra tags for Kubelet sync loop monitor | `list(string)` | `[]` | no | +| [kubelet\_syncloop\_message](#input\_kubelet\_syncloop\_message) | Custom message for Kubelet sync loop monitor | `string` | `""` | no | +| [kubelet\_syncloop\_threshold\_warning](#input\_kubelet\_syncloop\_threshold\_warning) | Kubelet sync loop monitor (warning threshold) | `string` | `3` | no | +| [memory\_pressure\_enabled](#input\_memory\_pressure\_enabled) | Flag to enable Memory pressure monitor | `string` | `"true"` | no | +| [memory\_pressure\_extra\_tags](#input\_memory\_pressure\_extra\_tags) | Extra tags for Memory pressure monitor | `list(string)` | `[]` | no | +| [memory\_pressure\_message](#input\_memory\_pressure\_message) | Custom message for Memory pressure monitor | `string` | `""` | no | +| [memory\_pressure\_threshold\_warning](#input\_memory\_pressure\_threshold\_warning) | Memory pressure monitor (warning threshold) | `string` | `3` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [node\_unschedulable\_enabled](#input\_node\_unschedulable\_enabled) | Flag to enable node unschedulable monitor | `string` | `"true"` | no | +| [node\_unschedulable\_extra\_tags](#input\_node\_unschedulable\_extra\_tags) | Extra tags for node unschedulable monitor | `list(string)` | `[]` | no | +| [node\_unschedulable\_message](#input\_node\_unschedulable\_message) | Custom message for node unschedulable monitor | `string` | `""` | no | +| [node\_unschedulable\_time\_aggregator](#input\_node\_unschedulable\_time\_aggregator) | Monitor aggregator for node unschedulable [available values: min, max or avg] | `string` | `"min"` | no | +| [node\_unschedulable\_timeframe](#input\_node\_unschedulable\_timeframe) | Monitor timeframe for node unschedulable [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1h"` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [ready\_enabled](#input\_ready\_enabled) | Flag to enable Node ready monitor | `string` | `"true"` | no | +| [ready\_extra\_tags](#input\_ready\_extra\_tags) | Extra tags for Node ready monitor | `list(string)` | `[]` | no | +| [ready\_message](#input\_ready\_message) | Custom message for Node ready monitor | `string` | `""` | no | +| [ready\_threshold\_warning](#input\_ready\_threshold\_warning) | Node ready monitor (warning threshold) | `string` | `3` | no | +| [unregister\_net\_device\_enabled](#input\_unregister\_net\_device\_enabled) | Flag to enable Unregister net device monitor | `string` | `"true"` | no | +| [unregister\_net\_device\_extra\_tags](#input\_unregister\_net\_device\_extra\_tags) | Extra tags for Unregister net device monitor | `list(string)` | `[]` | no | +| [unregister\_net\_device\_message](#input\_unregister\_net\_device\_message) | Custom message for Unregister net device monitor | `string` | `""` | no | +| [unregister\_net\_device\_threshold\_critical](#input\_unregister\_net\_device\_threshold\_critical) | Unregister net device critical threshold | `number` | `3` | no | +| [unregister\_net\_device\_time\_aggregator](#input\_unregister\_net\_device\_time\_aggregator) | Monitor aggregator for Unregister net device [available values: min, max or avg] | `string` | `"min"` | no | +| [unregister\_net\_device\_timeframe](#input\_unregister\_net\_device\_timeframe) | Monitor timeframe for Unregister net device [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"15m"` | no | +| [volume\_inodes\_enabled](#input\_volume\_inodes\_enabled) | Flag to enable Volume inodes monitor | `string` | `"true"` | no | +| [volume\_inodes\_extra\_tags](#input\_volume\_inodes\_extra\_tags) | Extra tags for Volume inodes monitor | `list(string)` | `[]` | no | +| [volume\_inodes\_message](#input\_volume\_inodes\_message) | Custom message for Volume inodes monitor | `string` | `""` | no | +| [volume\_inodes\_threshold\_critical](#input\_volume\_inodes\_threshold\_critical) | Volume inodes critical threshold | `number` | `95` | no | +| [volume\_inodes\_threshold\_warning](#input\_volume\_inodes\_threshold\_warning) | Volume inodes warning threshold | `number` | `90` | no | +| [volume\_inodes\_time\_aggregator](#input\_volume\_inodes\_time\_aggregator) | Monitor aggregator for Volume inodes [available values: min, max or avg] | `string` | `"min"` | no | +| [volume\_inodes\_timeframe](#input\_volume\_inodes\_timeframe) | Monitor timeframe for Volume inodes [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [volume\_space\_enabled](#input\_volume\_space\_enabled) | Flag to enable Volume space monitor | `string` | `"true"` | no | +| [volume\_space\_extra\_tags](#input\_volume\_space\_extra\_tags) | Extra tags for Volume space monitor | `list(string)` | `[]` | no | +| [volume\_space\_message](#input\_volume\_space\_message) | Custom message for Volume space monitor | `string` | `""` | no | +| [volume\_space\_threshold\_critical](#input\_volume\_space\_threshold\_critical) | Volume space critical threshold | `number` | `95` | no | +| [volume\_space\_threshold\_warning](#input\_volume\_space\_threshold\_warning) | Volume space warning threshold | `number` | `90` | no | +| [volume\_space\_time\_aggregator](#input\_volume\_space\_time\_aggregator) | Monitor aggregator for Volume space [available values: min, max or avg] | `string` | `"min"` | no | +| [volume\_space\_timeframe](#input\_volume\_space\_timeframe) | Monitor timeframe for Volume space [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [disk\_out\_id](#output\_disk\_out\_id) | id for monitor disk\_out | +| [disk\_pressure\_id](#output\_disk\_pressure\_id) | id for monitor disk\_pressure | +| [kubelet\_ping\_id](#output\_kubelet\_ping\_id) | id for monitor kubelet\_ping | +| [kubelet\_syncloop\_id](#output\_kubelet\_syncloop\_id) | id for monitor kubelet\_syncloop | +| [memory\_pressure\_id](#output\_memory\_pressure\_id) | id for monitor memory\_pressure | +| [node\_unschedulable\_id](#output\_node\_unschedulable\_id) | id for monitor node\_unschedulable | +| [ready\_id](#output\_ready\_id) | id for monitor ready | +| [unregister\_net\_device\_id](#output\_unregister\_net\_device\_id) | id for monitor unregister\_net\_device | +| [volume\_inodes\_id](#output\_volume\_inodes\_id) | id for monitor volume\_inodes | +| [volume\_space\_id](#output\_volume\_space\_id) | id for monitor volume\_space | +## Related documentation + +* [Datadog metrics](https://docs.datadoghq.com/agent/kubernetes/metrics/) +* [Datadog documentation](https://docs.datadoghq.com/integrations/kubernetes/) +* [Datadog Blog](https://www.datadoghq.com/blog/monitor-kubernetes-docker/) + +## Requirements + +* Datadog Agent > v6.6 diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/node/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/node/inputs.tf new file mode 100755 index 0000000..f45bd96 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/node/inputs.tf @@ -0,0 +1,342 @@ +# Datadog global variables + +variable "environment" { + description = "Architecture environment" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "kubelet_ping_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# Datadog monitors variables + +variable "disk_pressure_enabled" { + description = "Flag to enable Disk pressure monitor" + type = string + default = "true" +} + +variable "disk_pressure_extra_tags" { + description = "Extra tags for Disk pressure monitor" + type = list(string) + default = [] +} + +variable "disk_pressure_message" { + description = "Custom message for Disk pressure monitor" + type = string + default = "" +} + +variable "disk_pressure_threshold_warning" { + description = "Disk pressure monitor (warning threshold)" + type = string + default = 3 +} + +variable "disk_out_enabled" { + description = "Flag to enable Out of disk monitor" + type = string + default = "true" +} + +variable "disk_out_extra_tags" { + description = "Extra tags for Out of disk monitor" + type = list(string) + default = [] +} + +variable "disk_out_message" { + description = "Custom message for Out of disk monitor" + type = string + default = "" +} + +variable "disk_out_threshold_warning" { + description = "Out of disk monitor (warning threshold)" + type = string + default = 3 +} + +variable "memory_pressure_enabled" { + description = "Flag to enable Memory pressure monitor" + type = string + default = "true" +} + +variable "memory_pressure_extra_tags" { + description = "Extra tags for Memory pressure monitor" + type = list(string) + default = [] +} + +variable "memory_pressure_message" { + description = "Custom message for Memory pressure monitor" + type = string + default = "" +} + +variable "memory_pressure_threshold_warning" { + description = "Memory pressure monitor (warning threshold)" + type = string + default = 3 +} + +variable "ready_enabled" { + description = "Flag to enable Node ready monitor" + type = string + default = "true" +} + +variable "ready_extra_tags" { + description = "Extra tags for Node ready monitor" + type = list(string) + default = [] +} + +variable "ready_message" { + description = "Custom message for Node ready monitor" + type = string + default = "" +} + +variable "ready_threshold_warning" { + description = "Node ready monitor (warning threshold)" + type = string + default = 3 +} + +variable "kubelet_ping_enabled" { + description = "Flag to enable Kubelet ping monitor" + type = string + default = "true" +} + +variable "kubelet_ping_extra_tags" { + description = "Extra tags for Kubelet ping monitor" + type = list(string) + default = [] +} + +variable "kubelet_ping_message" { + description = "Custom message for Kubelet ping monitor" + type = string + default = "" +} + +variable "kubelet_ping_threshold_warning" { + description = "Kubelet ping monitor (warning threshold)" + type = string + default = 3 +} + +variable "kubelet_syncloop_enabled" { + description = "Flag to enable Kubelet sync loop monitor" + type = string + default = "true" +} + +variable "kubelet_syncloop_extra_tags" { + description = "Extra tags for Kubelet sync loop monitor" + type = list(string) + default = [] +} + +variable "kubelet_syncloop_message" { + description = "Custom message for Kubelet sync loop monitor" + type = string + default = "" +} + +variable "kubelet_syncloop_threshold_warning" { + description = "Kubelet sync loop monitor (warning threshold)" + type = string + default = 3 +} + +variable "unregister_net_device_enabled" { + description = "Flag to enable Unregister net device monitor" + type = string + default = "true" +} + +variable "unregister_net_device_extra_tags" { + description = "Extra tags for Unregister net device monitor" + type = list(string) + default = [] +} + +variable "unregister_net_device_message" { + description = "Custom message for Unregister net device monitor" + type = string + default = "" +} + +variable "unregister_net_device_time_aggregator" { + description = "Monitor aggregator for Unregister net device [available values: min, max or avg]" + type = string + default = "min" +} + +variable "unregister_net_device_timeframe" { + description = "Monitor timeframe for Unregister net device [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "15m" +} + +variable "unregister_net_device_threshold_critical" { + default = 3 + description = "Unregister net device critical threshold" +} + +variable "node_unschedulable_enabled" { + description = "Flag to enable node unschedulable monitor" + type = string + default = "true" +} + +variable "node_unschedulable_extra_tags" { + description = "Extra tags for node unschedulable monitor" + type = list(string) + default = [] +} + +variable "node_unschedulable_message" { + description = "Custom message for node unschedulable monitor" + type = string + default = "" +} + +variable "node_unschedulable_time_aggregator" { + description = "Monitor aggregator for node unschedulable [available values: min, max or avg]" + type = string + default = "min" +} + +variable "node_unschedulable_timeframe" { + description = "Monitor timeframe for node unschedulable [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1h" +} + +variable "volume_space_enabled" { + description = "Flag to enable Volume space monitor" + type = string + default = "true" +} + +variable "volume_space_extra_tags" { + description = "Extra tags for Volume space monitor" + type = list(string) + default = [] +} + +variable "volume_space_message" { + description = "Custom message for Volume space monitor" + type = string + default = "" +} + +variable "volume_space_time_aggregator" { + description = "Monitor aggregator for Volume space [available values: min, max or avg]" + type = string + default = "min" +} + +variable "volume_space_timeframe" { + description = "Monitor timeframe for Volume space [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "volume_space_threshold_critical" { + default = 95 + description = "Volume space critical threshold" +} + +variable "volume_space_threshold_warning" { + default = 90 + description = "Volume space warning threshold" +} + +variable "volume_inodes_enabled" { + description = "Flag to enable Volume inodes monitor" + type = string + default = "true" +} + +variable "volume_inodes_extra_tags" { + description = "Extra tags for Volume inodes monitor" + type = list(string) + default = [] +} + +variable "volume_inodes_message" { + description = "Custom message for Volume inodes monitor" + type = string + default = "" +} + +variable "volume_inodes_time_aggregator" { + description = "Monitor aggregator for Volume inodes [available values: min, max or avg]" + type = string + default = "min" +} + +variable "volume_inodes_timeframe" { + description = "Monitor timeframe for Volume inodes [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "volume_inodes_threshold_critical" { + default = 95 + description = "Volume inodes critical threshold" +} + +variable "volume_inodes_threshold_warning" { + default = 90 + description = "Volume inodes warning threshold" +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/node/modules.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/node/modules.tf new file mode 100755 index 0000000..20f05b0 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/node/modules.tf @@ -0,0 +1,21 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "kubernetes" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + +module "filter-tags-unschedulable" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "kubernetes" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["status:unschedulable"] +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/node/monitors-k8s-node.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/node/monitors-k8s-node.tf new file mode 100755 index 0000000..def810c --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/node/monitors-k8s-node.tf @@ -0,0 +1,275 @@ +resource "datadog_monitor" "disk_pressure" { + count = var.disk_pressure_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Kubernetes Node Disk pressure" + message = coalesce(var.disk_pressure_message, var.message) + type = "service check" + + query = < ${var.unregister_net_device_threshold_critical} +EOQ + + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + + tags = concat(["env:${var.environment}", "type:caas", "provider:kubernetes", "resource:kubernetes-node", "team:claranet", "created-by:terraform"], var.unregister_net_device_extra_tags) +} + +resource "datadog_monitor" "node_unschedulable" { + count = var.node_unschedulable_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Kubernetes Node unschedulable" + message = coalesce(var.node_unschedulable_message, var.message) + type = "metric alert" + + query = < 0 +EOQ + + monitor_thresholds { + critical = 0 + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:kubernetes", "resource:kubernetes-node", "team:claranet", "created-by:terraform"], var.node_unschedulable_extra_tags) +} + +resource "datadog_monitor" "volume_space" { + count = var.volume_space_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Kubernetes Node volume space usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.volume_space_message, var.message) + type = "query alert" + + query = < ${var.volume_space_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.volume_space_threshold_critical + warning = var.volume_space_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:kubernetes", "resource:kubernetes-node", "team:claranet", "created-by:terraform"], var.volume_space_extra_tags) +} + +resource "datadog_monitor" "volume_inodes" { + count = var.volume_inodes_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Kubernetes Node volume inodes usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.volume_inodes_message, var.message) + type = "query alert" + + query = < ${var.volume_inodes_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.volume_inodes_threshold_critical + warning = var.volume_inodes_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:kubernetes", "resource:kubernetes-node", "team:claranet", "created-by:terraform"], var.volume_inodes_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/node/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/node/outputs.tf new file mode 100755 index 0000000..553a82e --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/node/outputs.tf @@ -0,0 +1,50 @@ +output "disk_out_id" { + description = "id for monitor disk_out" + value = datadog_monitor.disk_out.*.id +} + +output "disk_pressure_id" { + description = "id for monitor disk_pressure" + value = datadog_monitor.disk_pressure.*.id +} + +output "kubelet_ping_id" { + description = "id for monitor kubelet_ping" + value = datadog_monitor.kubelet_ping.*.id +} + +output "kubelet_syncloop_id" { + description = "id for monitor kubelet_syncloop" + value = datadog_monitor.kubelet_syncloop.*.id +} + +output "memory_pressure_id" { + description = "id for monitor memory_pressure" + value = datadog_monitor.memory_pressure.*.id +} + +output "node_unschedulable_id" { + description = "id for monitor node_unschedulable" + value = datadog_monitor.node_unschedulable.*.id +} + +output "ready_id" { + description = "id for monitor ready" + value = datadog_monitor.ready.*.id +} + +output "unregister_net_device_id" { + description = "id for monitor unregister_net_device" + value = datadog_monitor.unregister_net_device.*.id +} + +output "volume_inodes_id" { + description = "id for monitor volume_inodes" + value = datadog_monitor.volume_inodes.*.id +} + +output "volume_space_id" { + description = "id for monitor volume_space" + value = datadog_monitor.volume_space.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/node/versions.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/node/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/node/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/pod/README.md b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/pod/README.md new file mode 100755 index 0000000..947267f --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/pod/README.md @@ -0,0 +1,101 @@ +# CAAS KUBERNETES POD DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-caas-kubernetes-pod" { + source = "claranet/monitors/datadog//caas/kubernetes/pod" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Kubernetes Pod phase status failed +- Kubernetes Pod terminated abnormally +- Kubernetes Pod waiting errors + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | +| [filter-tags-nocontainercreating](#module\_filter-tags-nocontainercreating) | ../../../common/filter-tags | n/a | +| [filter-tags-phase](#module\_filter-tags-phase) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.error](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.pod_phase_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.terminated](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `any` | n/a | yes | +| [error\_enabled](#input\_error\_enabled) | Flag to enable Pod errors monitor | `string` | `"true"` | no | +| [error\_extra\_tags](#input\_error\_extra\_tags) | Extra tags for Pod errors monitor | `list(string)` | `[]` | no | +| [error\_message](#input\_error\_message) | Custom message for Pod errors monitor | `string` | `""` | no | +| [error\_threshold\_critical](#input\_error\_threshold\_critical) | error critical threshold | `number` | `0.5` | no | +| [error\_threshold\_warning](#input\_error\_threshold\_warning) | error warning threshold | `number` | `0` | no | +| [error\_time\_aggregator](#input\_error\_time\_aggregator) | Monitor aggregator for Pod errors [available values: min, max or avg] | `string` | `"min"` | no | +| [error\_timeframe](#input\_error\_timeframe) | Monitor timeframe for Pod errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [pod\_phase\_status\_enabled](#input\_pod\_phase\_status\_enabled) | Flag to enable Pod phase status monitor | `string` | `"true"` | no | +| [pod\_phase\_status\_extra\_tags](#input\_pod\_phase\_status\_extra\_tags) | Extra tags for Pod phase status monitor | `list(string)` | `[]` | no | +| [pod\_phase\_status\_message](#input\_pod\_phase\_status\_message) | Custom message for Pod phase status monitor | `string` | `""` | no | +| [pod\_phase\_status\_time\_aggregator](#input\_pod\_phase\_status\_time\_aggregator) | Monitor aggregator for Pod phase status [available values: min, max or avg] | `string` | `"max"` | no | +| [pod\_phase\_status\_timeframe](#input\_pod\_phase\_status\_timeframe) | Monitor timeframe for Pod phase status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [terminated\_enabled](#input\_terminated\_enabled) | Flag to enable Pod terminated monitor | `string` | `"true"` | no | +| [terminated\_extra\_tags](#input\_terminated\_extra\_tags) | Extra tags for Pod terminated monitor | `list(string)` | `[]` | no | +| [terminated\_message](#input\_terminated\_message) | Custom message for Pod terminated monitor | `string` | `""` | no | +| [terminated\_threshold\_critical](#input\_terminated\_threshold\_critical) | terminated critical threshold | `number` | `0.5` | no | +| [terminated\_threshold\_warning](#input\_terminated\_threshold\_warning) | terminated warning threshold | `number` | `0` | no | +| [terminated\_time\_aggregator](#input\_terminated\_time\_aggregator) | Monitor aggregator for Pod terminated [available values: min, max or avg] | `string` | `"sum"` | no | +| [terminated\_timeframe](#input\_terminated\_timeframe) | Monitor timeframe for Pod terminated [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_10m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [error\_id](#output\_error\_id) | id for monitor error | +| [pod\_phase\_status\_id](#output\_pod\_phase\_status\_id) | id for monitor pod\_phase\_status | +| [terminated\_id](#output\_terminated\_id) | id for monitor terminated | +## Related documentation + +* [Datadog metrics](https://docs.datadoghq.com/agent/kubernetes/metrics/) +* [Datadog documentation](https://docs.datadoghq.com/integrations/kubernetes/) +* [Datadog Blog](https://www.datadoghq.com/blog/monitor-kubernetes-docker/) + +## Requirements + +* Datadog Agent > v7.2 diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/pod/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/pod/inputs.tf new file mode 100755 index 0000000..cdf6687 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/pod/inputs.tf @@ -0,0 +1,157 @@ +# Datadog global variables + +variable "environment" { + description = "Architecture environment" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# Datadog monitors variables + +variable "pod_phase_status_enabled" { + description = "Flag to enable Pod phase status monitor" + type = string + default = "true" +} + +variable "pod_phase_status_extra_tags" { + description = "Extra tags for Pod phase status monitor" + type = list(string) + default = [] +} + +variable "pod_phase_status_message" { + description = "Custom message for Pod phase status monitor" + type = string + default = "" +} + +variable "pod_phase_status_time_aggregator" { + description = "Monitor aggregator for Pod phase status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "pod_phase_status_timeframe" { + description = "Monitor timeframe for Pod phase status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "error_enabled" { + description = "Flag to enable Pod errors monitor" + type = string + default = "true" +} + +variable "error_extra_tags" { + description = "Extra tags for Pod errors monitor" + type = list(string) + default = [] +} + +variable "error_message" { + description = "Custom message for Pod errors monitor" + type = string + default = "" +} + +variable "error_time_aggregator" { + description = "Monitor aggregator for Pod errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "error_timeframe" { + description = "Monitor timeframe for Pod errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "error_threshold_critical" { + default = 0.5 + description = "error critical threshold" +} + +variable "error_threshold_warning" { + default = 0 + description = "error warning threshold" +} + +variable "terminated_enabled" { + description = "Flag to enable Pod terminated monitor" + type = string + default = "true" +} + +variable "terminated_extra_tags" { + description = "Extra tags for Pod terminated monitor" + type = list(string) + default = [] +} + +variable "terminated_message" { + description = "Custom message for Pod terminated monitor" + type = string + default = "" +} + +variable "terminated_time_aggregator" { + description = "Monitor aggregator for Pod terminated [available values: min, max or avg]" + type = string + default = "sum" +} + +variable "terminated_timeframe" { + description = "Monitor timeframe for Pod terminated [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_10m" +} + +variable "terminated_threshold_critical" { + default = 0.5 + description = "terminated critical threshold" +} + +variable "terminated_threshold_warning" { + default = 0 + description = "terminated warning threshold" +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/pod/modules.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/pod/modules.tf new file mode 100755 index 0000000..eb818f5 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/pod/modules.tf @@ -0,0 +1,32 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "kubernetes" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + +module "filter-tags-phase" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "kubernetes" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags_excluded = ["phase:pending,phase:running,phase:succeeded,phase:unknown"] +} + +module "filter-tags-nocontainercreating" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "kubernetes" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags_excluded = ["reason:containercreating"] +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/pod/monitors-k8s-pod.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/pod/monitors-k8s-pod.tf new file mode 100755 index 0000000..53da50f --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/pod/monitors-k8s-pod.tf @@ -0,0 +1,89 @@ +resource "datadog_monitor" "pod_phase_status" { + count = var.pod_phase_status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Kubernetes Pod phase status failed" + message = coalesce(var.pod_phase_status_message, var.message) + type = "metric alert" + + query = < 0 +EOQ + + monitor_thresholds { + critical = 0 + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:kubernetes", "resource:kubernetes-pod", "team:claranet", "created-by:terraform"], var.pod_phase_status_extra_tags) +} + +resource "datadog_monitor" "error" { + count = var.error_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Kubernetes Pod waiting errors" + message = coalesce(var.error_message, var.message) + type = "query alert" + + query = < ${var.error_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.error_threshold_critical + warning = var.error_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:kubernetes", "resource:kubernetes-pod", "team:claranet", "created-by:terraform"], var.error_extra_tags) +} + +resource "datadog_monitor" "terminated" { + count = var.terminated_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Kubernetes Pod terminated abnormally" + message = coalesce(var.terminated_message, var.message) + type = "query alert" + + query = < ${var.terminated_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.terminated_threshold_critical + warning = var.terminated_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:kubernetes", "resource:kubernetes-pod", "team:claranet", "created-by:terraform"], var.terminated_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/pod/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/pod/outputs.tf new file mode 100755 index 0000000..1e71580 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/pod/outputs.tf @@ -0,0 +1,15 @@ +output "error_id" { + description = "id for monitor error" + value = datadog_monitor.error.*.id +} + +output "pod_phase_status_id" { + description = "id for monitor pod_phase_status" + value = datadog_monitor.pod_phase_status.*.id +} + +output "terminated_id" { + description = "id for monitor terminated" + value = datadog_monitor.terminated.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/pod/versions.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/pod/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/pod/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/velero/README.md b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/velero/README.md new file mode 100755 index 0000000..7df2d36 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/velero/README.md @@ -0,0 +1,176 @@ +# CAAS KUBERNETES VELERO DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-caas-kubernetes-velero" { + source = "claranet/monitors/datadog//caas/kubernetes/velero" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Velero backup deletion failure +- Velero backup failure +- Velero backup partial failure +- Velero scheduled backup missing +- Velero volume snapshot failure + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | +| [filter-tags-scheduled-backup](#module\_filter-tags-scheduled-backup) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.velero_backup_deletion_failure](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.velero_backup_failure](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.velero_backup_partial_failure](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.velero_scheduled_backup_missing](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.velero_volume_snapshot_failure](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `any` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [velero\_backup\_deletion\_failure\_enabled](#input\_velero\_backup\_deletion\_failure\_enabled) | Flag to enable Velero backup deletion failure monitor | `string` | `"true"` | no | +| [velero\_backup\_deletion\_failure\_extra\_tags](#input\_velero\_backup\_deletion\_failure\_extra\_tags) | Extra tags for Velero backup deletion failure monitor | `list(string)` | `[]` | no | +| [velero\_backup\_deletion\_failure\_monitor\_message](#input\_velero\_backup\_deletion\_failure\_monitor\_message) | Custom message for Velero backup deletion failure monitor | `string` | `""` | no | +| [velero\_backup\_deletion\_failure\_monitor\_timeframe](#input\_velero\_backup\_deletion\_failure\_monitor\_timeframe) | Monitor timeframe for Velero backup deletion failure monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1d"` | no | +| [velero\_backup\_failure\_enabled](#input\_velero\_backup\_failure\_enabled) | Flag to enable Velero backup failure monitor | `string` | `"true"` | no | +| [velero\_backup\_failure\_extra\_tags](#input\_velero\_backup\_failure\_extra\_tags) | Extra tags for Velero backup failure monitor | `list(string)` | `[]` | no | +| [velero\_backup\_failure\_monitor\_message](#input\_velero\_backup\_failure\_monitor\_message) | Custom message for Velero backup failure monitor | `string` | `""` | no | +| [velero\_backup\_failure\_monitor\_timeframe](#input\_velero\_backup\_failure\_monitor\_timeframe) | Monitor timeframe for Velero backup failure monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1d"` | no | +| [velero\_backup\_partial\_failure\_enabled](#input\_velero\_backup\_partial\_failure\_enabled) | Flag to enable Velero backup partial failure monitor | `string` | `"true"` | no | +| [velero\_backup\_partial\_failure\_extra\_tags](#input\_velero\_backup\_partial\_failure\_extra\_tags) | Extra tags for Velero backup partial failure monitor | `list(string)` | `[]` | no | +| [velero\_backup\_partial\_failure\_monitor\_message](#input\_velero\_backup\_partial\_failure\_monitor\_message) | Custom message for Velero backup partial failure monitor | `string` | `""` | no | +| [velero\_backup\_partial\_failure\_monitor\_timeframe](#input\_velero\_backup\_partial\_failure\_monitor\_timeframe) | Monitor timeframe for Velero backup partial failure monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1d"` | no | +| [velero\_scheduled\_backup\_missing\_enabled](#input\_velero\_scheduled\_backup\_missing\_enabled) | Flag to enable Velero scheduled backup missing monitor | `string` | `"true"` | no | +| [velero\_scheduled\_backup\_missing\_extra\_tags](#input\_velero\_scheduled\_backup\_missing\_extra\_tags) | Extra tags for Velero scheduled backup missing monitor | `list(string)` | `[]` | no | +| [velero\_scheduled\_backup\_missing\_monitor\_message](#input\_velero\_scheduled\_backup\_missing\_monitor\_message) | Custom message for Velero scheduled backup missing monitor | `string` | `""` | no | +| [velero\_scheduled\_backup\_missing\_monitor\_no\_data\_timeframe](#input\_velero\_scheduled\_backup\_missing\_monitor\_no\_data\_timeframe) | No data timeframe in minutes | `number` | `2880` | no | +| [velero\_scheduled\_backup\_missing\_monitor\_timeframe](#input\_velero\_scheduled\_backup\_missing\_monitor\_timeframe) | Monitor timeframe for Velero scheduled backup missing monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1d"` | no | +| [velero\_volume\_snapshot\_failure\_enabled](#input\_velero\_volume\_snapshot\_failure\_enabled) | Flag to enable Velero volume snapshot failure monitor | `string` | `"true"` | no | +| [velero\_volume\_snapshot\_failure\_extra\_tags](#input\_velero\_volume\_snapshot\_failure\_extra\_tags) | Extra tags for Velero volume snapshot failure monitor | `list(string)` | `[]` | no | +| [velero\_volume\_snapshot\_failure\_monitor\_message](#input\_velero\_volume\_snapshot\_failure\_monitor\_message) | Custom message for Velero volume snapshot failure monitor | `string` | `""` | no | +| [velero\_volume\_snapshot\_failure\_monitor\_timeframe](#input\_velero\_volume\_snapshot\_failure\_monitor\_timeframe) | Monitor timeframe for Velero volume snapshot failure monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1d"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [velero\_backup\_deletion\_failure\_id](#output\_velero\_backup\_deletion\_failure\_id) | id for monitor velero\_backup\_deletion\_failure | +| [velero\_backup\_failure\_id](#output\_velero\_backup\_failure\_id) | id for monitor velero\_backup\_failure | +| [velero\_backup\_partial\_failure\_id](#output\_velero\_backup\_partial\_failure\_id) | id for monitor velero\_backup\_partial\_failure | +| [velero\_scheduled\_backup\_missing\_id](#output\_velero\_scheduled\_backup\_missing\_id) | id for monitor velero\_scheduled\_backup\_missing | +| [velero\_volume\_snapshot\_failure\_id](#output\_velero\_volume\_snapshot\_failure\_id) | id for monitor velero\_volume\_snapshot\_failure | +## Related documentation + +Documentation for Datadog prometheus intergration: https://docs.datadoghq.com/integrations/prometheus/ +Documentation for Datadog OpenMetrics integration: https://docs.datadoghq.com/integrations/openmetrics/ +Documentation for Datadog autodiscovery: https://docs.datadoghq.com/agent/autodiscovery/clusterchecks/ + +### How to configure Datadog agent for these monitors ? +You can configure Datadog agent by autodiscovery pod annotations or by configuration file. + +#### Configuration by autodiscovery pod annotations +Add these annotations to Velero pods: + +``` +podAnnotations: { + "ad.datadoghq.com/velero.check_names": '["openmetrics"]', + "ad.datadoghq.com/velero.init_configs": '[{}]', + "ad.datadoghq.com/velero.instances": '[{"prometheus_url": "http://%%host%%:8085/metrics", "namespace": "velero", "metrics": ["velero*"]}]' +} +``` + +#### Configuration by configuration file +Example of `openmetrics.d/conf.yaml`: + +``` +init_config: + +instances: + + ## @param prometheus_url - string - required + ## The URL where your application metrics are exposed by Prometheus. + # + - prometheus_url: http://velero.velero.svc.cluster.local:8085/metrics + + ## @param namespace - string - required + ## The namespace to be prepended to all metrics. + # + namespace: "velero" + + ## @param metrics - list of strings - required + ## List of metrics to be fetched from the prometheus endpoint, if there's a + ## value it'll be renamed. This list should contain at least one metric + # + metrics: + - velero* +``` + +### How to monitor multiple schedule witch have different frequencies ? + +If you have multiple Velero schedules with different frequencies, you must duplicate the default example module declaration specifying right timeframes and disabling others common monitors. + +For instance, for an hourly schedule you can uncomment this block: + +``` +#module "datadog-monitors-caas-kubernetes-velero" { +# source = "claranet/monitors/datadog//caas/kubernetes/velero" +# version = "{revision}" +# +# environment = var.environment +# message = module.datadog-message-alerting.alerting-message +#} + +#module "datadog-monitors-caas-kubernetes-velero-hourly" { +# source = "claranet/monitors/datadog//caas/kubernetes/velero" +# version = "{revision}" +# +# environment = var.environment +# message = module.datadog-message-alerting.alerting-message +# +# velero_scheduled_backup_missing_monitor_timeframe = "last_1h" +# velero_scheduled_backup_missing_monitor_no_data_timeframe = 120 +# velero_backup_failure_enabled = false +# velero_backup_partial_failure_enabled = false +# velero_backup_deletion_failure_enabled = false +# velero_volume_snapshot_failure_enabled = false +#} +``` + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/velero/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/velero/inputs.tf new file mode 100755 index 0000000..755cd6a --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/velero/inputs.tf @@ -0,0 +1,171 @@ +# Datadog global variables + +variable "environment" { + description = "Architecture environment" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# Datadog monitors variables + +variable "velero_scheduled_backup_missing_monitor_message" { + description = "Custom message for Velero scheduled backup missing monitor" + type = string + default = "" +} + +variable "velero_scheduled_backup_missing_monitor_timeframe" { + description = "Monitor timeframe for Velero scheduled backup missing monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1d" +} + +variable "velero_scheduled_backup_missing_enabled" { + description = "Flag to enable Velero scheduled backup missing monitor" + type = string + default = "true" +} + +variable "velero_scheduled_backup_missing_extra_tags" { + description = "Extra tags for Velero scheduled backup missing monitor" + type = list(string) + default = [] +} + +variable "velero_scheduled_backup_missing_monitor_no_data_timeframe" { + description = "No data timeframe in minutes" + default = 2880 +} + +variable "velero_backup_failure_monitor_message" { + description = "Custom message for Velero backup failure monitor" + type = string + default = "" +} + +variable "velero_backup_failure_monitor_timeframe" { + description = "Monitor timeframe for Velero backup failure monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1d" +} + +variable "velero_backup_failure_enabled" { + description = "Flag to enable Velero backup failure monitor" + type = string + default = "true" +} + +variable "velero_backup_failure_extra_tags" { + description = "Extra tags for Velero backup failure monitor" + type = list(string) + default = [] +} + +variable "velero_backup_partial_failure_monitor_message" { + description = "Custom message for Velero backup partial failure monitor" + type = string + default = "" +} + +variable "velero_backup_partial_failure_monitor_timeframe" { + description = "Monitor timeframe for Velero backup partial failure monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1d" +} + +variable "velero_backup_partial_failure_enabled" { + description = "Flag to enable Velero backup partial failure monitor" + type = string + default = "true" +} + +variable "velero_backup_partial_failure_extra_tags" { + description = "Extra tags for Velero backup partial failure monitor" + type = list(string) + default = [] +} + +variable "velero_backup_deletion_failure_monitor_message" { + description = "Custom message for Velero backup deletion failure monitor" + type = string + default = "" +} + +variable "velero_backup_deletion_failure_monitor_timeframe" { + description = "Monitor timeframe for Velero backup deletion failure monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1d" +} + +variable "velero_backup_deletion_failure_enabled" { + description = "Flag to enable Velero backup deletion failure monitor" + type = string + default = "true" +} + +variable "velero_backup_deletion_failure_extra_tags" { + description = "Extra tags for Velero backup deletion failure monitor" + type = list(string) + default = [] +} + +variable "velero_volume_snapshot_failure_monitor_message" { + description = "Custom message for Velero volume snapshot failure monitor" + type = string + default = "" +} + +variable "velero_volume_snapshot_failure_monitor_timeframe" { + description = "Monitor timeframe for Velero volume snapshot failure monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1d" +} + +variable "velero_volume_snapshot_failure_enabled" { + description = "Flag to enable Velero volume snapshot failure monitor" + type = string + default = "true" +} + +variable "velero_volume_snapshot_failure_extra_tags" { + description = "Extra tags for Velero volume snapshot failure monitor" + type = list(string) + default = [] +} diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/velero/modules.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/velero/modules.tf new file mode 100755 index 0000000..c1cb2b3 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/velero/modules.tf @@ -0,0 +1,20 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "velero" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + +module "filter-tags-scheduled-backup" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "velero" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags_excluded = ["schedule:"] +} diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/velero/monitors-velero.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/velero/monitors-velero.tf new file mode 100755 index 0000000..12b0539 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/velero/monitors-velero.tf @@ -0,0 +1,145 @@ +resource "datadog_monitor" "velero_scheduled_backup_missing" { + count = var.velero_scheduled_backup_missing_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Velero scheduled backup missing" + type = "query alert" + message = coalesce(var.velero_scheduled_backup_missing_monitor_message, var.message) + + query = < 1 +EOQ + + monitor_thresholds { + critical = 1 + warning = 0 + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:openmetrics", "resource:velero", "team:claranet", "created-by:terraform"], var.velero_backup_failure_extra_tags) +} + +resource "datadog_monitor" "velero_backup_partial_failure" { + count = var.velero_backup_partial_failure_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Velero backup partial failure" + type = "query alert" + message = coalesce(var.velero_backup_partial_failure_monitor_message, var.message) + + query = < 1 +EOQ + + monitor_thresholds { + critical = 1 + warning = 0 + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:openmetrics", "resource:velero", "team:claranet", "created-by:terraform"], var.velero_backup_partial_failure_extra_tags) +} + +resource "datadog_monitor" "velero_backup_deletion_failure" { + count = var.velero_backup_deletion_failure_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Velero backup deletion failure" + type = "query alert" + message = coalesce(var.velero_backup_deletion_failure_monitor_message, var.message) + + query = < 1 +EOQ + + monitor_thresholds { + critical = 1 + warning = 0 + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:openmetrics", "resource:velero", "team:claranet", "created-by:terraform"], var.velero_backup_deletion_failure_extra_tags) +} + +resource "datadog_monitor" "velero_volume_snapshot_failure" { + count = var.velero_volume_snapshot_failure_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Velero volume snapshot failure" + type = "query alert" + message = coalesce(var.velero_volume_snapshot_failure_monitor_message, var.message) + + query = < 1 +EOQ + + monitor_thresholds { + critical = 1 + warning = 0 + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:caas", "provider:openmetrics", "resource:velero", "team:claranet", "created-by:terraform"], var.velero_volume_snapshot_failure_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/velero/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/velero/outputs.tf new file mode 100755 index 0000000..992a26b --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/velero/outputs.tf @@ -0,0 +1,25 @@ +output "velero_backup_deletion_failure_id" { + description = "id for monitor velero_backup_deletion_failure" + value = datadog_monitor.velero_backup_deletion_failure.*.id +} + +output "velero_backup_failure_id" { + description = "id for monitor velero_backup_failure" + value = datadog_monitor.velero_backup_failure.*.id +} + +output "velero_backup_partial_failure_id" { + description = "id for monitor velero_backup_partial_failure" + value = datadog_monitor.velero_backup_partial_failure.*.id +} + +output "velero_scheduled_backup_missing_id" { + description = "id for monitor velero_scheduled_backup_missing" + value = datadog_monitor.velero_scheduled_backup_missing.*.id +} + +output "velero_volume_snapshot_failure_id" { + description = "id for monitor velero_volume_snapshot_failure" + value = datadog_monitor.velero_volume_snapshot_failure.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/velero/versions.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/velero/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/velero/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/workload/README.md b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/workload/README.md new file mode 100755 index 0000000..1503175 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/workload/README.md @@ -0,0 +1,112 @@ +# CAAS KUBERNETES WORKLOAD DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-caas-kubernetes-workload" { + source = "claranet/monitors/datadog//caas/kubernetes/workload" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Kubernetes Available replicas +- Kubernetes cronjob scheduling failed +- Kubernetes Current replicas +- Kubernetes job failed +- Kubernetes Ready replicas + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cronjob](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.job](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.replica_available](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.replica_current](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.replica_ready](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cronjob\_enabled](#input\_cronjob\_enabled) | Flag to enable Cronjob monitor | `string` | `"true"` | no | +| [cronjob\_extra\_tags](#input\_cronjob\_extra\_tags) | Extra tags for Cronjob monitor | `list(string)` | `[]` | no | +| [cronjob\_message](#input\_cronjob\_message) | Custom message for Cronjob monitor | `string` | `""` | no | +| [cronjob\_threshold\_warning](#input\_cronjob\_threshold\_warning) | Cronjob monitor (warning threshold) | `string` | `3` | no | +| [environment](#input\_environment) | Architecture environment | `any` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [job\_enabled](#input\_job\_enabled) | Flag to enable Job monitor | `string` | `"true"` | no | +| [job\_extra\_tags](#input\_job\_extra\_tags) | Extra tags for Job monitor | `list(string)` | `[]` | no | +| [job\_message](#input\_job\_message) | Custom message for Job monitor | `string` | `""` | no | +| [job\_threshold\_warning](#input\_job\_threshold\_warning) | Job monitor (warning threshold) | `string` | `3` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [replica\_available\_enabled](#input\_replica\_available\_enabled) | Flag to enable Available replica monitor | `string` | `"true"` | no | +| [replica\_available\_extra\_tags](#input\_replica\_available\_extra\_tags) | Extra tags for Available replicamonitor | `list(string)` | `[]` | no | +| [replica\_available\_message](#input\_replica\_available\_message) | Custom message for Available replica monitor | `string` | `""` | no | +| [replica\_available\_threshold\_critical](#input\_replica\_available\_threshold\_critical) | Available replica critical threshold | `number` | `1` | no | +| [replica\_available\_time\_aggregator](#input\_replica\_available\_time\_aggregator) | Monitor aggregator for Available replica [available values: min, max or avg] | `string` | `"max"` | no | +| [replica\_available\_timeframe](#input\_replica\_available\_timeframe) | Monitor timeframe for Available replica [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [replica\_current\_enabled](#input\_replica\_current\_enabled) | Flag to enable Current replica monitor | `string` | `"true"` | no | +| [replica\_current\_extra\_tags](#input\_replica\_current\_extra\_tags) | Extra tags for Current replica monitor | `list(string)` | `[]` | no | +| [replica\_current\_message](#input\_replica\_current\_message) | Custom message for Current replica monitor | `string` | `""` | no | +| [replica\_current\_threshold\_critical](#input\_replica\_current\_threshold\_critical) | Current replica critical threshold | `number` | `1` | no | +| [replica\_current\_time\_aggregator](#input\_replica\_current\_time\_aggregator) | Monitor aggregator for Current replica [available values: min, max or avg] | `string` | `"max"` | no | +| [replica\_current\_timeframe](#input\_replica\_current\_timeframe) | Monitor timeframe for Current replica [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [replica\_ready\_enabled](#input\_replica\_ready\_enabled) | Flag to enable Ready replica monitor | `string` | `"true"` | no | +| [replica\_ready\_extra\_tags](#input\_replica\_ready\_extra\_tags) | Extra tags for Ready replica monitor | `list(string)` | `[]` | no | +| [replica\_ready\_message](#input\_replica\_ready\_message) | Custom message for Ready replica monitor | `string` | `""` | no | +| [replica\_ready\_threshold\_critical](#input\_replica\_ready\_threshold\_critical) | Ready replica critical threshold | `number` | `1` | no | +| [replica\_ready\_time\_aggregator](#input\_replica\_ready\_time\_aggregator) | Monitor aggregator for Ready replica [available values: min, max or avg] | `string` | `"max"` | no | +| [replica\_ready\_timeframe](#input\_replica\_ready\_timeframe) | Monitor timeframe for Ready replica [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cronjob\_id](#output\_cronjob\_id) | id for monitor cronjob | +| [job\_id](#output\_job\_id) | id for monitor job | +| [replica\_available\_id](#output\_replica\_available\_id) | id for monitor replica\_available | +| [replica\_current\_id](#output\_replica\_current\_id) | id for monitor replica\_current | +| [replica\_ready\_id](#output\_replica\_ready\_id) | id for monitor replica\_ready | +## Related documentation + +* [Datadog metrics](https://docs.datadoghq.com/agent/kubernetes/metrics/) +* [Datadog documentation](https://docs.datadoghq.com/integrations/kubernetes/) +* [Datadog Blog](https://www.datadoghq.com/blog/monitor-kubernetes-docker/) + +## Requirements + +* Datadog Agent > v6.6 diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/workload/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/workload/inputs.tf new file mode 100755 index 0000000..6c44b2b --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/workload/inputs.tf @@ -0,0 +1,200 @@ +# Datadog global variables + +variable "environment" { + description = "Architecture environment" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# Datadog monitors variables + +variable "job_enabled" { + description = "Flag to enable Job monitor" + type = string + default = "true" +} + +variable "job_extra_tags" { + description = "Extra tags for Job monitor" + type = list(string) + default = [] +} + +variable "job_message" { + description = "Custom message for Job monitor" + type = string + default = "" +} + +variable "job_threshold_warning" { + description = "Job monitor (warning threshold)" + type = string + default = 3 +} + +variable "cronjob_enabled" { + description = "Flag to enable Cronjob monitor" + type = string + default = "true" +} + +variable "cronjob_extra_tags" { + description = "Extra tags for Cronjob monitor" + type = list(string) + default = [] +} + +variable "cronjob_message" { + description = "Custom message for Cronjob monitor" + type = string + default = "" +} + +variable "cronjob_threshold_warning" { + description = "Cronjob monitor (warning threshold)" + type = string + default = 3 +} + +variable "replica_available_enabled" { + description = "Flag to enable Available replica monitor" + type = string + default = "true" +} + +variable "replica_available_extra_tags" { + description = "Extra tags for Available replicamonitor" + type = list(string) + default = [] +} + +variable "replica_available_message" { + description = "Custom message for Available replica monitor" + type = string + default = "" +} + +variable "replica_available_time_aggregator" { + description = "Monitor aggregator for Available replica [available values: min, max or avg]" + type = string + default = "max" +} + +variable "replica_available_timeframe" { + description = "Monitor timeframe for Available replica [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "replica_available_threshold_critical" { + default = 1 + description = "Available replica critical threshold" +} + +variable "replica_ready_enabled" { + description = "Flag to enable Ready replica monitor" + type = string + default = "true" +} + +variable "replica_ready_extra_tags" { + description = "Extra tags for Ready replica monitor" + type = list(string) + default = [] +} + +variable "replica_ready_message" { + description = "Custom message for Ready replica monitor" + type = string + default = "" +} + +variable "replica_ready_time_aggregator" { + description = "Monitor aggregator for Ready replica [available values: min, max or avg]" + type = string + default = "max" +} + +variable "replica_ready_timeframe" { + description = "Monitor timeframe for Ready replica [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "replica_ready_threshold_critical" { + default = 1 + description = "Ready replica critical threshold" +} + +variable "replica_current_enabled" { + description = "Flag to enable Current replica monitor" + type = string + default = "true" +} + +variable "replica_current_extra_tags" { + description = "Extra tags for Current replica monitor" + type = list(string) + default = [] +} + +variable "replica_current_message" { + description = "Custom message for Current replica monitor" + type = string + default = "" +} + +variable "replica_current_time_aggregator" { + description = "Monitor aggregator for Current replica [available values: min, max or avg]" + type = string + default = "max" +} + +variable "replica_current_timeframe" { + description = "Monitor timeframe for Current replica [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "replica_current_threshold_critical" { + default = 1 + description = "Current replica critical threshold" +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/workload/modules.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/workload/modules.tf new file mode 100755 index 0000000..a57cf43 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/workload/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "kubernetes" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/workload/monitors-k8s-workload.tf b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/workload/monitors-k8s-workload.tf new file mode 100755 index 0000000..41ebbb4 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/caas/kubernetes/workload/monitors-k8s-workload.tf @@ -0,0 +1,144 @@ +resource "datadog_monitor" "job" { + count = var.job_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Kubernetes job failed" + message = coalesce(var.job_message, var.message) + type = "service check" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.ALB_httpcode_4xx](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ALB_httpcode_5xx](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ALB_httpcode_target_4xx](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ALB_httpcode_target_5xx](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ALB_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ALB_no_healthy_instances](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [alb\_no\_healthy\_instances\_enabled](#input\_alb\_no\_healthy\_instances\_enabled) | Flag to enable ALB no healthy instances monitor | `string` | `"true"` | no | +| [alb\_no\_healthy\_instances\_extra\_tags](#input\_alb\_no\_healthy\_instances\_extra\_tags) | Extra tags for ALB no healthy instances monitor | `list(string)` | `[]` | no | +| [alb\_no\_healthy\_instances\_message](#input\_alb\_no\_healthy\_instances\_message) | Custom message for ALB no healthy instances monitor | `string` | `""` | no | +| [alb\_no\_healthy\_instances\_no\_data\_timeframe](#input\_alb\_no\_healthy\_instances\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [alb\_no\_healthy\_instances\_threshold\_warning](#input\_alb\_no\_healthy\_instances\_threshold\_warning) | ALB no healthy instances warning threshold in percentage | `number` | `100` | no | +| [alb\_no\_healthy\_instances\_time\_aggregator](#input\_alb\_no\_healthy\_instances\_time\_aggregator) | Monitor aggregator for ALB no healthy instances [available values: min, max or avg] | `string` | `"min"` | no | +| [alb\_no\_healthy\_instances\_timeframe](#input\_alb\_no\_healthy\_instances\_timeframe) | Monitor timeframe for ALB no healthy instances [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [artificial\_requests\_count](#input\_artificial\_requests\_count) | Number of false requests used to mitigate false positive in case of low trafic | `number` | `5` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [httpcode\_alb\_4xx\_enabled](#input\_httpcode\_alb\_4xx\_enabled) | Flag to enable ALB httpcode 4xx monitor | `string` | `"true"` | no | +| [httpcode\_alb\_4xx\_extra\_tags](#input\_httpcode\_alb\_4xx\_extra\_tags) | Extra tags for ALB httpcode 4xx monitor | `list(string)` | `[]` | no | +| [httpcode\_alb\_4xx\_message](#input\_httpcode\_alb\_4xx\_message) | Custom message for ALB httpcode 4xx monitor | `string` | `""` | no | +| [httpcode\_alb\_4xx\_threshold\_critical](#input\_httpcode\_alb\_4xx\_threshold\_critical) | loadbalancer 4xx critical threshold in percentage | `number` | `80` | no | +| [httpcode\_alb\_4xx\_threshold\_warning](#input\_httpcode\_alb\_4xx\_threshold\_warning) | loadbalancer 4xx warning threshold in percentage | `number` | `60` | no | +| [httpcode\_alb\_4xx\_time\_aggregator](#input\_httpcode\_alb\_4xx\_time\_aggregator) | Monitor aggregator for ALB httpcode 4xx [available values: min, max or avg] | `string` | `"min"` | no | +| [httpcode\_alb\_4xx\_timeframe](#input\_httpcode\_alb\_4xx\_timeframe) | Monitor timeframe for ALB httpcode 4xx [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [httpcode\_alb\_5xx\_enabled](#input\_httpcode\_alb\_5xx\_enabled) | Flag to enable ALB httpcode 5xx monitor | `string` | `"true"` | no | +| [httpcode\_alb\_5xx\_extra\_tags](#input\_httpcode\_alb\_5xx\_extra\_tags) | Extra tags for ALB httpcode 5xx monitor | `list(string)` | `[]` | no | +| [httpcode\_alb\_5xx\_message](#input\_httpcode\_alb\_5xx\_message) | Custom message for ALB httpcode 5xx monitor | `string` | `""` | no | +| [httpcode\_alb\_5xx\_threshold\_critical](#input\_httpcode\_alb\_5xx\_threshold\_critical) | loadbalancer 5xx critical threshold in percentage | `number` | `80` | no | +| [httpcode\_alb\_5xx\_threshold\_warning](#input\_httpcode\_alb\_5xx\_threshold\_warning) | loadbalancer 5xx warning threshold in percentage | `number` | `60` | no | +| [httpcode\_alb\_5xx\_time\_aggregator](#input\_httpcode\_alb\_5xx\_time\_aggregator) | Monitor aggregator for ALB httpcode 5xx [available values: min, max or avg] | `string` | `"min"` | no | +| [httpcode\_alb\_5xx\_timeframe](#input\_httpcode\_alb\_5xx\_timeframe) | Monitor timeframe for ALB httpcode 5xx [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [httpcode\_target\_4xx\_enabled](#input\_httpcode\_target\_4xx\_enabled) | Flag to enable ALB target httpcode 4xx monitor | `string` | `"true"` | no | +| [httpcode\_target\_4xx\_extra\_tags](#input\_httpcode\_target\_4xx\_extra\_tags) | Extra tags for ALB target httpcode 4xx monitor | `list(string)` | `[]` | no | +| [httpcode\_target\_4xx\_message](#input\_httpcode\_target\_4xx\_message) | Custom message for ALB target httpcode 4xx monitor | `string` | `""` | no | +| [httpcode\_target\_4xx\_threshold\_critical](#input\_httpcode\_target\_4xx\_threshold\_critical) | target 4xx critical threshold in percentage | `number` | `80` | no | +| [httpcode\_target\_4xx\_threshold\_warning](#input\_httpcode\_target\_4xx\_threshold\_warning) | target 4xx warning threshold in percentage | `number` | `60` | no | +| [httpcode\_target\_4xx\_time\_aggregator](#input\_httpcode\_target\_4xx\_time\_aggregator) | Monitor aggregator for ALB target httpcode 4xx [available values: min, max or avg] | `string` | `"min"` | no | +| [httpcode\_target\_4xx\_timeframe](#input\_httpcode\_target\_4xx\_timeframe) | Monitor timeframe for ALB target httpcode 4xx [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [httpcode\_target\_5xx\_enabled](#input\_httpcode\_target\_5xx\_enabled) | Flag to enable ALB target httpcode 5xx monitor | `string` | `"true"` | no | +| [httpcode\_target\_5xx\_extra\_tags](#input\_httpcode\_target\_5xx\_extra\_tags) | Extra tags for ALB target httpcode 5xx monitor | `list(string)` | `[]` | no | +| [httpcode\_target\_5xx\_message](#input\_httpcode\_target\_5xx\_message) | Custom message for ALB target httpcode 5xx monitor | `string` | `""` | no | +| [httpcode\_target\_5xx\_threshold\_critical](#input\_httpcode\_target\_5xx\_threshold\_critical) | target 5xx critical threshold in percentage | `number` | `80` | no | +| [httpcode\_target\_5xx\_threshold\_warning](#input\_httpcode\_target\_5xx\_threshold\_warning) | target 5xx warning threshold in percentage | `number` | `60` | no | +| [httpcode\_target\_5xx\_time\_aggregator](#input\_httpcode\_target\_5xx\_time\_aggregator) | Monitor aggregator for ALB target httpcode 5xx [available values: min, max or avg] | `string` | `"min"` | no | +| [httpcode\_target\_5xx\_timeframe](#input\_httpcode\_target\_5xx\_timeframe) | Monitor timeframe for ALB target httpcode 5xx [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [latency\_enabled](#input\_latency\_enabled) | Flag to enable ALB latency monitor | `string` | `"true"` | no | +| [latency\_extra\_tags](#input\_latency\_extra\_tags) | Extra tags for ALB latency monitor | `list(string)` | `[]` | no | +| [latency\_message](#input\_latency\_message) | Custom message for ALB latency monitor | `string` | `""` | no | +| [latency\_threshold\_critical](#input\_latency\_threshold\_critical) | latency critical threshold in seconds | `number` | `3` | no | +| [latency\_threshold\_warning](#input\_latency\_threshold\_warning) | latency warning threshold in seconds | `number` | `1` | no | +| [latency\_time\_aggregator](#input\_latency\_time\_aggregator) | Monitor aggregator for ALB latency [available values: min, max or avg] | `string` | `"min"` | no | +| [latency\_timeframe](#input\_latency\_timeframe) | Monitor timeframe for ALB latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [ALB\_httpcode\_4xx\_id](#output\_ALB\_httpcode\_4xx\_id) | id for monitor ALB\_httpcode\_4xx | +| [ALB\_httpcode\_5xx\_id](#output\_ALB\_httpcode\_5xx\_id) | id for monitor ALB\_httpcode\_5xx | +| [ALB\_httpcode\_target\_4xx\_id](#output\_ALB\_httpcode\_target\_4xx\_id) | id for monitor ALB\_httpcode\_target\_4xx | +| [ALB\_httpcode\_target\_5xx\_id](#output\_ALB\_httpcode\_target\_5xx\_id) | id for monitor ALB\_httpcode\_target\_5xx | +| [ALB\_latency\_id](#output\_ALB\_latency\_id) | id for monitor ALB\_latency | +| [ALB\_no\_healthy\_instances\_id](#output\_ALB\_no\_healthy\_instances\_id) | id for monitor ALB\_no\_healthy\_instances | +## Related documentation + +DataDog blog: [https://www.datadoghq.com/blog/monitor-application-load-balancer/](https://www.datadoghq.com/blog/monitor-application-load-balancer/) + +AWS ALB metrics documentation: [https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-cloudwatch-metrics.html](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-cloudwatch-metrics.html) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/alb/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/alb/inputs.tf new file mode 100755 index 0000000..e175bef --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/alb/inputs.tf @@ -0,0 +1,294 @@ +# Datadog global variables + +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "alb_no_healthy_instances_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# Datadog monitors variables + +variable "alb_no_healthy_instances_enabled" { + description = "Flag to enable ALB no healthy instances monitor" + type = string + default = "true" +} + +variable "alb_no_healthy_instances_extra_tags" { + description = "Extra tags for ALB no healthy instances monitor" + type = list(string) + default = [] +} + +variable "alb_no_healthy_instances_message" { + description = "Custom message for ALB no healthy instances monitor" + type = string + default = "" +} + +variable "alb_no_healthy_instances_time_aggregator" { + description = "Monitor aggregator for ALB no healthy instances [available values: min, max or avg]" + type = string + default = "min" +} + +variable "alb_no_healthy_instances_timeframe" { + description = "Monitor timeframe for ALB no healthy instances [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "alb_no_healthy_instances_threshold_warning" { + description = "ALB no healthy instances warning threshold in percentage" + default = 100 +} + +variable "latency_enabled" { + description = "Flag to enable ALB latency monitor" + type = string + default = "true" +} + +variable "latency_extra_tags" { + description = "Extra tags for ALB latency monitor" + type = list(string) + default = [] +} + +variable "latency_message" { + description = "Custom message for ALB latency monitor" + type = string + default = "" +} + +variable "latency_time_aggregator" { + description = "Monitor aggregator for ALB latency [available values: min, max or avg]" + type = string + default = "min" +} + +variable "latency_timeframe" { + description = "Monitor timeframe for ALB latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "latency_threshold_critical" { + default = 3 + description = "latency critical threshold in seconds" +} + +variable "latency_threshold_warning" { + default = 1 + description = "latency warning threshold in seconds" +} + +variable "httpcode_alb_4xx_enabled" { + description = "Flag to enable ALB httpcode 4xx monitor" + type = string + default = "true" +} + +variable "httpcode_alb_4xx_extra_tags" { + description = "Extra tags for ALB httpcode 4xx monitor" + type = list(string) + default = [] +} + +variable "httpcode_alb_4xx_message" { + description = "Custom message for ALB httpcode 4xx monitor" + type = string + default = "" +} + +variable "httpcode_alb_4xx_time_aggregator" { + description = "Monitor aggregator for ALB httpcode 4xx [available values: min, max or avg]" + type = string + default = "min" +} + +variable "httpcode_alb_4xx_timeframe" { + description = "Monitor timeframe for ALB httpcode 4xx [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "httpcode_alb_4xx_threshold_critical" { + default = 80 + description = "loadbalancer 4xx critical threshold in percentage" +} + +variable "httpcode_alb_4xx_threshold_warning" { + default = 60 + description = "loadbalancer 4xx warning threshold in percentage" +} + +variable "httpcode_target_4xx_enabled" { + description = "Flag to enable ALB target httpcode 4xx monitor" + type = string + default = "true" +} + +variable "httpcode_target_4xx_extra_tags" { + description = "Extra tags for ALB target httpcode 4xx monitor" + type = list(string) + default = [] +} + +variable "httpcode_target_4xx_message" { + description = "Custom message for ALB target httpcode 4xx monitor" + type = string + default = "" +} + +variable "httpcode_target_4xx_time_aggregator" { + description = "Monitor aggregator for ALB target httpcode 4xx [available values: min, max or avg]" + type = string + default = "min" +} + +variable "httpcode_target_4xx_timeframe" { + description = "Monitor timeframe for ALB target httpcode 4xx [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "httpcode_target_4xx_threshold_critical" { + default = 80 + description = "target 4xx critical threshold in percentage" +} + +variable "httpcode_target_4xx_threshold_warning" { + default = 60 + description = "target 4xx warning threshold in percentage" +} + +variable "httpcode_alb_5xx_enabled" { + description = "Flag to enable ALB httpcode 5xx monitor" + type = string + default = "true" +} + +variable "httpcode_alb_5xx_extra_tags" { + description = "Extra tags for ALB httpcode 5xx monitor" + type = list(string) + default = [] +} + +variable "httpcode_alb_5xx_message" { + description = "Custom message for ALB httpcode 5xx monitor" + type = string + default = "" +} + +variable "httpcode_alb_5xx_time_aggregator" { + description = "Monitor aggregator for ALB httpcode 5xx [available values: min, max or avg]" + type = string + default = "min" +} + +variable "httpcode_alb_5xx_timeframe" { + description = "Monitor timeframe for ALB httpcode 5xx [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "httpcode_alb_5xx_threshold_critical" { + default = 80 + description = "loadbalancer 5xx critical threshold in percentage" +} + +variable "httpcode_alb_5xx_threshold_warning" { + default = 60 + description = "loadbalancer 5xx warning threshold in percentage" +} + +variable "httpcode_target_5xx_enabled" { + description = "Flag to enable ALB target httpcode 5xx monitor" + type = string + default = "true" +} + +variable "httpcode_target_5xx_extra_tags" { + description = "Extra tags for ALB target httpcode 5xx monitor" + type = list(string) + default = [] +} + +variable "httpcode_target_5xx_message" { + description = "Custom message for ALB target httpcode 5xx monitor" + type = string + default = "" +} + +variable "httpcode_target_5xx_time_aggregator" { + description = "Monitor aggregator for ALB target httpcode 5xx [available values: min, max or avg]" + type = string + default = "min" +} + +variable "httpcode_target_5xx_timeframe" { + description = "Monitor timeframe for ALB target httpcode 5xx [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "httpcode_target_5xx_threshold_critical" { + default = 80 + description = "target 5xx critical threshold in percentage" +} + +variable "httpcode_target_5xx_threshold_warning" { + default = 60 + description = "target 5xx warning threshold in percentage" +} + +variable "artificial_requests_count" { + default = 5 + description = "Number of false requests used to mitigate false positive in case of low trafic" +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/alb/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/alb/modules.tf new file mode 100755 index 0000000..480c3d6 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/alb/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "aws_alb" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/alb/monitors-alb.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/alb/monitors-alb.tf new file mode 100755 index 0000000..36f4b8d --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/alb/monitors-alb.tf @@ -0,0 +1,175 @@ +resource "datadog_monitor" "ALB_no_healthy_instances" { + count = var.alb_no_healthy_instances_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ALB healthy instances {{#is_alert}}is at 0{{/is_alert}}{{#is_warning}}is at {{value}}%%{{/is_warning}}" + message = coalesce(var.alb_no_healthy_instances_message, var.message) + type = "query alert" + + query = < ${var.latency_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.latency_threshold_critical + warning = var.latency_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:alb", "team:claranet", "created-by:terraform"], var.latency_extra_tags) +} + +resource "datadog_monitor" "ALB_httpcode_5xx" { + count = var.httpcode_alb_5xx_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ALB HTTP code 5xx {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.httpcode_alb_5xx_message, var.message) + type = "query alert" + + query = < ${var.httpcode_alb_5xx_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.httpcode_alb_5xx_threshold_critical + warning = var.httpcode_alb_5xx_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:alb", "team:claranet", "created-by:terraform"], var.httpcode_alb_5xx_extra_tags) +} + +resource "datadog_monitor" "ALB_httpcode_4xx" { + count = var.httpcode_alb_4xx_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ALB HTTP code 4xx {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.httpcode_alb_4xx_message, var.message) + type = "query alert" + + query = < ${var.httpcode_alb_4xx_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.httpcode_alb_4xx_threshold_critical + warning = var.httpcode_alb_4xx_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:alb", "team:claranet", "created-by:terraform"], var.httpcode_alb_4xx_extra_tags) +} + +resource "datadog_monitor" "ALB_httpcode_target_5xx" { + count = var.httpcode_target_5xx_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ALB target HTTP code 5xx {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.httpcode_target_5xx_message, var.message) + type = "query alert" + + query = < ${var.httpcode_target_5xx_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.httpcode_target_5xx_threshold_critical + warning = var.httpcode_target_5xx_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:alb", "team:claranet", "created-by:terraform"], var.httpcode_target_5xx_extra_tags) +} + +resource "datadog_monitor" "ALB_httpcode_target_4xx" { + count = var.httpcode_target_4xx_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ALB target HTTP code 4xx {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.httpcode_target_4xx_message, var.message) + type = "query alert" + + query = < ${var.httpcode_target_4xx_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.httpcode_target_4xx_threshold_critical + warning = var.httpcode_target_4xx_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:alb", "team:claranet", "created-by:terraform"], var.httpcode_target_4xx_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/alb/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/alb/outputs.tf new file mode 100755 index 0000000..f2e72d1 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/alb/outputs.tf @@ -0,0 +1,30 @@ +output "ALB_httpcode_4xx_id" { + description = "id for monitor ALB_httpcode_4xx" + value = datadog_monitor.ALB_httpcode_4xx.*.id +} + +output "ALB_httpcode_5xx_id" { + description = "id for monitor ALB_httpcode_5xx" + value = datadog_monitor.ALB_httpcode_5xx.*.id +} + +output "ALB_httpcode_target_4xx_id" { + description = "id for monitor ALB_httpcode_target_4xx" + value = datadog_monitor.ALB_httpcode_target_4xx.*.id +} + +output "ALB_httpcode_target_5xx_id" { + description = "id for monitor ALB_httpcode_target_5xx" + value = datadog_monitor.ALB_httpcode_target_5xx.*.id +} + +output "ALB_latency_id" { + description = "id for monitor ALB_latency" + value = datadog_monitor.ALB_latency.*.id +} + +output "ALB_no_healthy_instances_id" { + description = "id for monitor ALB_no_healthy_instances" + value = datadog_monitor.ALB_no_healthy_instances.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/alb/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/alb/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/alb/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/apigateway/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/apigateway/README.md new file mode 100755 index 0000000..a080e78 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/apigateway/README.md @@ -0,0 +1,94 @@ +# CLOUD AWS APIGATEWAY DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-apigateway" { + source = "claranet/monitors/datadog//cloud/aws/apigateway" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- API Gateway HTTP 4xx errors +- API Gateway HTTP 5xx errors +- API Gateway latency + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.API_Gateway_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.API_http_4xx_errors_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.API_http_5xx_errors_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [artificial\_requests\_count](#input\_artificial\_requests\_count) | Number of false requests used to mitigate false positive in case of low trafic | `number` | `5` | no | +| [environment](#input\_environment) | Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags](#input\_filter\_tags) | Tags used for filtering | `string` | `"*"` | no | +| [http\_4xx\_requests\_enabled](#input\_http\_4xx\_requests\_enabled) | Flag to enable API Gateway HTTP 4xx requests monitor | `string` | `"true"` | no | +| [http\_4xx\_requests\_extra\_tags](#input\_http\_4xx\_requests\_extra\_tags) | Extra tags for API Gateway HTTP 4xx requests monitor | `list(string)` | `[]` | no | +| [http\_4xx\_requests\_message](#input\_http\_4xx\_requests\_message) | Custom message for API Gateway HTTP 4xx requests monitor | `string` | `""` | no | +| [http\_4xx\_requests\_threshold\_critical](#input\_http\_4xx\_requests\_threshold\_critical) | Maximum critical acceptable percent of 4xx errors | `number` | `30` | no | +| [http\_4xx\_requests\_threshold\_warning](#input\_http\_4xx\_requests\_threshold\_warning) | Maximum warning acceptable percent of 4xx errors | `number` | `15` | no | +| [http\_4xx\_requests\_time\_aggregator](#input\_http\_4xx\_requests\_time\_aggregator) | Monitor aggregator for API HTTP 4xx requests [available values: min, max or avg] | `string` | `"min"` | no | +| [http\_4xx\_requests\_timeframe](#input\_http\_4xx\_requests\_timeframe) | Monitor timeframe for API HTTP 4xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [http\_5xx\_requests\_enabled](#input\_http\_5xx\_requests\_enabled) | Flag to enable API Gateway HTTP 5xx requests monitor | `string` | `"true"` | no | +| [http\_5xx\_requests\_extra\_tags](#input\_http\_5xx\_requests\_extra\_tags) | Extra tags for API Gateway HTTP 5xx requests monitor | `list(string)` | `[]` | no | +| [http\_5xx\_requests\_message](#input\_http\_5xx\_requests\_message) | Custom message for API Gateway HTTP 5xx requests monitor | `string` | `""` | no | +| [http\_5xx\_requests\_threshold\_critical](#input\_http\_5xx\_requests\_threshold\_critical) | Maximum critical acceptable percent of 5xx errors | `number` | `20` | no | +| [http\_5xx\_requests\_threshold\_warning](#input\_http\_5xx\_requests\_threshold\_warning) | Maximum warning acceptable percent of 5xx errors | `number` | `10` | no | +| [http\_5xx\_requests\_time\_aggregator](#input\_http\_5xx\_requests\_time\_aggregator) | Monitor aggregator for API HTTP 5xx requests [available values: min, max or avg] | `string` | `"min"` | no | +| [http\_5xx\_requests\_timeframe](#input\_http\_5xx\_requests\_timeframe) | Monitor timeframe for API HTTP 5xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [latency\_enabled](#input\_latency\_enabled) | Flag to enable API Gateway latency monitor | `string` | `"true"` | no | +| [latency\_extra\_tags](#input\_latency\_extra\_tags) | Extra tags for API Gateway latency monitor | `list(string)` | `[]` | no | +| [latency\_message](#input\_latency\_message) | Custom message for API Gateway latency monitor | `string` | `""` | no | +| [latency\_threshold\_critical](#input\_latency\_threshold\_critical) | Alerting threshold in milliseconds | `number` | `3000` | no | +| [latency\_threshold\_warning](#input\_latency\_threshold\_warning) | Warning threshold in milliseconds | `number` | `1000` | no | +| [latency\_time\_aggregator](#input\_latency\_time\_aggregator) | Monitor aggregator for API Gateway latency [available values: min, max or avg] | `string` | `"min"` | no | +| [latency\_timeframe](#input\_latency\_timeframe) | Monitor timeframe for API latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [API\_Gateway\_latency\_id](#output\_API\_Gateway\_latency\_id) | id for monitor API\_Gateway\_latency | +| [API\_http\_4xx\_errors\_count\_id](#output\_API\_http\_4xx\_errors\_count\_id) | id for monitor API\_http\_4xx\_errors\_count | +| [API\_http\_5xx\_errors\_count\_id](#output\_API\_http\_5xx\_errors\_count\_id) | id for monitor API\_http\_5xx\_errors\_count | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/amazon_api_gateway/](https://docs.datadoghq.com/integrations/amazon_api_gateway/) + +AWS API Gateway metrics documentation: [https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/api-gateway-metrics-dimensions.html](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/api-gateway-metrics-dimensions.html) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/apigateway/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/apigateway/inputs.tf new file mode 100755 index 0000000..174bc15 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/apigateway/inputs.tf @@ -0,0 +1,171 @@ +variable "environment" { + description = "Environment" + type = string +} + +variable "filter_tags" { + description = "Tags used for filtering" + default = "*" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +################################### +### LATENCY VARIABLES ### +################################### + +variable "latency_enabled" { + description = "Flag to enable API Gateway latency monitor" + type = string + default = "true" +} + +variable "latency_extra_tags" { + description = "Extra tags for API Gateway latency monitor" + type = list(string) + default = [] +} + +variable "latency_message" { + description = "Custom message for API Gateway latency monitor" + type = string + default = "" +} + +variable "latency_time_aggregator" { + description = "Monitor aggregator for API Gateway latency [available values: min, max or avg]" + type = string + default = "min" +} + +variable "latency_timeframe" { + description = "Monitor timeframe for API latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "latency_threshold_critical" { + default = 3000 + description = "Alerting threshold in milliseconds" +} + +variable "latency_threshold_warning" { + default = 1000 + description = "Warning threshold in milliseconds" +} + +################################# +### HTTP 5xx status pages ### +################################# + +variable "http_5xx_requests_enabled" { + description = "Flag to enable API Gateway HTTP 5xx requests monitor" + type = string + default = "true" +} + +variable "http_5xx_requests_extra_tags" { + description = "Extra tags for API Gateway HTTP 5xx requests monitor" + type = list(string) + default = [] +} + +variable "http_5xx_requests_message" { + description = "Custom message for API Gateway HTTP 5xx requests monitor" + type = string + default = "" +} + +variable "http_5xx_requests_time_aggregator" { + description = "Monitor aggregator for API HTTP 5xx requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "http_5xx_requests_timeframe" { + description = "Monitor timeframe for API HTTP 5xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "http_5xx_requests_threshold_critical" { + default = 20 + description = "Maximum critical acceptable percent of 5xx errors" +} + +variable "http_5xx_requests_threshold_warning" { + default = 10 + description = "Maximum warning acceptable percent of 5xx errors" +} + +################################# +### HTTP 4xx status pages ### +################################# + +variable "http_4xx_requests_enabled" { + description = "Flag to enable API Gateway HTTP 4xx requests monitor" + type = string + default = "true" +} + +variable "http_4xx_requests_extra_tags" { + description = "Extra tags for API Gateway HTTP 4xx requests monitor" + type = list(string) + default = [] +} + +variable "http_4xx_requests_message" { + description = "Custom message for API Gateway HTTP 4xx requests monitor" + type = string + default = "" +} + +variable "http_4xx_requests_time_aggregator" { + description = "Monitor aggregator for API HTTP 4xx requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "http_4xx_requests_timeframe" { + description = "Monitor timeframe for API HTTP 4xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "http_4xx_requests_threshold_critical" { + default = 30 + description = "Maximum critical acceptable percent of 4xx errors" +} + +variable "http_4xx_requests_threshold_warning" { + default = 15 + description = "Maximum warning acceptable percent of 4xx errors" +} + +variable "artificial_requests_count" { + default = 5 + description = "Number of false requests used to mitigate false positive in case of low trafic" +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/apigateway/monitors-api.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/apigateway/monitors-api.tf new file mode 100755 index 0000000..18bfa8f --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/apigateway/monitors-api.tf @@ -0,0 +1,89 @@ +# Monitoring Api Gateway latency +resource "datadog_monitor" "API_Gateway_latency" { + count = var.latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] API Gateway latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.latency_message, var.message) + type = "query alert" + + query = < ${var.latency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.latency_threshold_warning + critical = var.latency_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:apigateway", "team:claranet", "created-by:terraform"], var.latency_extra_tags) +} + +# Monitoring API Gateway 5xx errors percent +resource "datadog_monitor" "API_http_5xx_errors_count" { + count = var.http_5xx_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] API Gateway HTTP 5xx errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.http_5xx_requests_message, var.message) + type = "query alert" + + query = < ${var.http_5xx_requests_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.http_5xx_requests_threshold_warning + critical = var.http_5xx_requests_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 1 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:apigateway", "team:claranet", "created-by:terraform"], var.http_5xx_requests_extra_tags) +} + +# Monitoring API Gateway 4xx errors percent +resource "datadog_monitor" "API_http_4xx_errors_count" { + count = var.http_4xx_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] API Gateway HTTP 4xx errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.http_4xx_requests_message, var.message) + type = "query alert" + + query = < ${var.http_4xx_requests_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.http_4xx_requests_threshold_warning + critical = var.http_4xx_requests_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 1 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:apigateway", "team:claranet", "created-by:terraform"], var.http_4xx_requests_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/apigateway/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/apigateway/outputs.tf new file mode 100755 index 0000000..9c411dc --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/apigateway/outputs.tf @@ -0,0 +1,15 @@ +output "API_Gateway_latency_id" { + description = "id for monitor API_Gateway_latency" + value = datadog_monitor.API_Gateway_latency.*.id +} + +output "API_http_4xx_errors_count_id" { + description = "id for monitor API_http_4xx_errors_count" + value = datadog_monitor.API_http_4xx_errors_count.*.id +} + +output "API_http_5xx_errors_count_id" { + description = "id for monitor API_http_5xx_errors_count" + value = datadog_monitor.API_http_5xx_errors_count.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/apigateway/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/apigateway/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/apigateway/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/beanstalk/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/beanstalk/README.md new file mode 100755 index 0000000..7239061 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/beanstalk/README.md @@ -0,0 +1,110 @@ +# CLOUD AWS BEANSTALK DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-beanstalk" { + source = "claranet/monitors/datadog//cloud/aws/beanstalk" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Beanstalk Application 5xx error rate +- Beanstalk Application latency p90 +- Beanstalk Environment health +- Beanstalk Instance root file system usage + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | +| [filter-tags-no-host](#module\_filter-tags-no-host) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.application_5xx_error_rate](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.application_latency_p90](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.health](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.root_filesystem_usage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [application\_5xx\_error\_rate\_enabled](#input\_application\_5xx\_error\_rate\_enabled) | Flag to enable Beanstalk application 5xx error ratemonitor | `string` | `"true"` | no | +| [application\_5xx\_error\_rate\_extra\_tags](#input\_application\_5xx\_error\_rate\_extra\_tags) | Extra tags for application 5xx error rate monitor | `list(string)` | `[]` | no | +| [application\_5xx\_error\_rate\_message](#input\_application\_5xx\_error\_rate\_message) | Custom message for application 5xx error rate | `string` | `""` | no | +| [application\_5xx\_error\_rate\_threshold\_critical](#input\_application\_5xx\_error\_rate\_threshold\_critical) | 5xx Error rate critical threshold in percent | `number` | `5` | no | +| [application\_5xx\_error\_rate\_threshold\_warning](#input\_application\_5xx\_error\_rate\_threshold\_warning) | 5xx Error rate warning threshold in percent | `string` | `3` | no | +| [application\_5xx\_error\_rate\_time\_aggregator](#input\_application\_5xx\_error\_rate\_time\_aggregator) | Monitor aggregator for beanstalk application 5xx error rate [available values: min, max or avg] | `string` | `"sum"` | no | +| [application\_5xx\_error\_rate\_timeframe](#input\_application\_5xx\_error\_rate\_timeframe) | Monitor timeframe for beanstalk application 5xx error rate [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [application\_latency\_p90\_enabled](#input\_application\_latency\_p90\_enabled) | Flag to enable Beanstalk application latency P90 monitor | `string` | `"true"` | no | +| [application\_latency\_p90\_extra\_tags](#input\_application\_latency\_p90\_extra\_tags) | Extra tags for application latency P90 monitor | `list(string)` | `[]` | no | +| [application\_latency\_p90\_message](#input\_application\_latency\_p90\_message) | Custom message for application latency P90 monitor | `string` | `""` | no | +| [application\_latency\_p90\_threshold\_critical](#input\_application\_latency\_p90\_threshold\_critical) | P90 Latency critical threshold in seconds | `number` | `0.5` | no | +| [application\_latency\_p90\_threshold\_warning](#input\_application\_latency\_p90\_threshold\_warning) | P90 Latency warning threshold in seconds | `string` | `0.3` | no | +| [application\_latency\_p90\_time\_aggregator](#input\_application\_latency\_p90\_time\_aggregator) | Monitor aggregator for beanstalk application latency P90 [available values: min, max or avg] | `string` | `"min"` | no | +| [application\_latency\_p90\_timeframe](#input\_application\_latency\_p90\_timeframe) | Monitor timeframe for beanstalk application latency P90 [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [health\_enabled](#input\_health\_enabled) | Flag to enable Beanstalk Health monitor | `string` | `"true"` | no | +| [health\_extra\_tags](#input\_health\_extra\_tags) | Extra tags for health monitor | `list(string)` | `[]` | no | +| [health\_message](#input\_health\_message) | Custom message for health monitor | `string` | `""` | no | +| [health\_no\_data\_timeframe](#input\_health\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `20` | no | +| [health\_threshold\_critical](#input\_health\_threshold\_critical) | Health critical threshold (see the `aws.elasticbeanstalk.environment_health` values in the Datadog documentation) | `number` | `20` | no | +| [health\_threshold\_warning](#input\_health\_threshold\_warning) | Health critical threshold (see the `aws.elasticbeanstalk.environment_health` values in the Datadog documentation) | `number` | `15` | no | +| [health\_time\_aggregator](#input\_health\_time\_aggregator) | Monitor aggregator for beanstalk health [available values: min, max or avg] | `string` | `"min"` | no | +| [health\_timeframe](#input\_health\_timeframe) | Monitor timeframe for beanstalk health [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_10m"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [root\_filesystem\_usage\_aggregator](#input\_root\_filesystem\_usage\_aggregator) | Monitor aggregator for beanstalk instance file system usage [available values: min, max or avg] | `string` | `"max"` | no | +| [root\_filesystem\_usage\_enabled](#input\_root\_filesystem\_usage\_enabled) | Flag to enable Beanstalk instance file system usage monitor | `string` | `"true"` | no | +| [root\_filesystem\_usage\_extra\_tags](#input\_root\_filesystem\_usage\_extra\_tags) | Extra tags for file system usage monitor | `list(string)` | `[]` | no | +| [root\_filesystem\_usage\_message](#input\_root\_filesystem\_usage\_message) | Custom message for application file system usage | `string` | `""` | no | +| [root\_filesystem\_usage\_threshold\_critical](#input\_root\_filesystem\_usage\_threshold\_critical) | File system usage critical threshold in percent | `string` | `90` | no | +| [root\_filesystem\_usage\_threshold\_warning](#input\_root\_filesystem\_usage\_threshold\_warning) | File system usage warning threshold in percent | `string` | `80` | no | +| [root\_filesystem\_usage\_timeframe](#input\_root\_filesystem\_usage\_timeframe) | Monitor timeframe for beanstalk instance file system usage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [root\_filesystem\_usage\_timeout\_h](#input\_root\_filesystem\_usage\_timeout\_h) | File system usage auto-resolving state (in hours) | `number` | `0` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [application\_5xx\_error\_rate\_id](#output\_application\_5xx\_error\_rate\_id) | id for monitor application\_5xx\_error\_rate | +| [application\_latency\_p90\_id](#output\_application\_latency\_p90\_id) | id for monitor application\_latency\_p90 | +| [health\_id](#output\_health\_id) | id for monitor health | +| [root\_filesystem\_usage\_id](#output\_root\_filesystem\_usage\_id) | id for monitor root\_filesystem\_usage | +## Related documentation + +Datadog documentation: [https://docs.datadoghq.com/integrations/amazon_elasticbeanstalk/](https://docs.datadoghq.com/integrations/amazon_elasticbeanstalk/) + +AWS Beanstalk Environment monitoring : [https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-health.html](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-health.html) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/beanstalk/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/beanstalk/inputs.tf new file mode 100755 index 0000000..fbdf773 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/beanstalk/inputs.tf @@ -0,0 +1,219 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "health_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 20 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# AWS Beanstalk monitor variables + +variable "health_enabled" { + description = "Flag to enable Beanstalk Health monitor" + type = string + default = "true" +} + +variable "health_message" { + description = "Custom message for health monitor" + default = "" +} + +variable "health_time_aggregator" { + description = "Monitor aggregator for beanstalk health [available values: min, max or avg]" + type = string + default = "min" +} + +variable "health_timeframe" { + description = "Monitor timeframe for beanstalk health [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_10m" +} + +variable "health_threshold_critical" { + description = "Health critical threshold (see the `aws.elasticbeanstalk.environment_health` values in the Datadog documentation)" + default = 20 +} + +variable "health_threshold_warning" { + description = "Health critical threshold (see the `aws.elasticbeanstalk.environment_health` values in the Datadog documentation)" + default = 15 +} + +variable "health_extra_tags" { + description = "Extra tags for health monitor" + type = list(string) + default = [] +} + +variable "application_latency_p90_enabled" { + description = "Flag to enable Beanstalk application latency P90 monitor" + type = string + default = "true" +} + +variable "application_latency_p90_message" { + description = "Custom message for application latency P90 monitor" + default = "" +} + +variable "application_latency_p90_time_aggregator" { + description = "Monitor aggregator for beanstalk application latency P90 [available values: min, max or avg]" + type = string + default = "min" +} + +variable "application_latency_p90_timeframe" { + description = "Monitor timeframe for beanstalk application latency P90 [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "application_latency_p90_threshold_critical" { + description = "P90 Latency critical threshold in seconds" + default = 0.5 +} + +variable "application_latency_p90_threshold_warning" { + description = "P90 Latency warning threshold in seconds" + type = string + default = 0.3 +} + +variable "application_latency_p90_extra_tags" { + description = "Extra tags for application latency P90 monitor" + type = list(string) + default = [] +} + +variable "application_5xx_error_rate_enabled" { + description = "Flag to enable Beanstalk application 5xx error ratemonitor" + type = string + default = "true" +} + +variable "application_5xx_error_rate_message" { + description = "Custom message for application 5xx error rate" + default = "" +} + +variable "application_5xx_error_rate_time_aggregator" { + description = "Monitor aggregator for beanstalk application 5xx error rate [available values: min, max or avg]" + type = string + default = "sum" +} + +variable "application_5xx_error_rate_timeframe" { + description = "Monitor timeframe for beanstalk application 5xx error rate [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "application_5xx_error_rate_threshold_critical" { + description = "5xx Error rate critical threshold in percent" + default = 5 +} + +variable "application_5xx_error_rate_threshold_warning" { + description = "5xx Error rate warning threshold in percent" + type = string + default = 3 +} + +variable "application_5xx_error_rate_extra_tags" { + description = "Extra tags for application 5xx error rate monitor" + type = list(string) + default = [] +} + +variable "root_filesystem_usage_enabled" { + description = "Flag to enable Beanstalk instance file system usage monitor" + type = string + default = "true" +} + +variable "root_filesystem_usage_message" { + description = "Custom message for application file system usage" + default = "" +} + +variable "root_filesystem_usage_aggregator" { + description = "Monitor aggregator for beanstalk instance file system usage [available values: min, max or avg]" + type = string + default = "max" +} + +variable "root_filesystem_usage_timeframe" { + description = "Monitor timeframe for beanstalk instance file system usage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "root_filesystem_usage_threshold_critical" { + description = "File system usage critical threshold in percent" + type = string + default = 90 +} + +variable "root_filesystem_usage_threshold_warning" { + description = "File system usage warning threshold in percent" + type = string + default = 80 +} + +variable "root_filesystem_usage_timeout_h" { + description = "File system usage auto-resolving state (in hours)" + default = 0 +} + +variable "root_filesystem_usage_extra_tags" { + description = "Extra tags for file system usage monitor" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/beanstalk/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/beanstalk/modules.tf new file mode 100755 index 0000000..560dd86 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/beanstalk/modules.tf @@ -0,0 +1,34 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "aws_beanstalk" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + +# With AWS beanstalk some metrics are send per host and per beanstalk env. +# This is particularly the case for all the ApplicationLatency metrics and +# the ApplicationRequests (not for the health and the cpu/disk metrics). +# The best way to find this out is to go on the monitoring configuration page +# of your beanstalk environment. +# +# In order to differentiate those metrics we need to do some exclusion to +# to find out which values has been sent for the host and the one sent for +# the environment itself. +# Some automatic tags are added on the instances by AWS, this seems to be +# the only way to filter at the moment. +# +# This filter exclude the metrics sent for the hosts. +module "filter-tags-no-host" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "aws_beanstalk" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags_excluded = ["aws_cloudformation_logical-id:awsebautoscalinggroup"] +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/beanstalk/monitors-beanstalk.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/beanstalk/monitors-beanstalk.tf new file mode 100755 index 0000000..c620372 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/beanstalk/monitors-beanstalk.tf @@ -0,0 +1,110 @@ +### Beanstalk environment health ### +resource "datadog_monitor" "health" { + count = var.health_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Beanstalk Environment health {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}} : either degraded or severe){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}} : warning){{/is_warning}}" + message = coalesce(var.health_message, var.message) + type = "metric alert" + + query = <= ${var.health_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.health_threshold_critical + warning = var.health_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = var.notify_no_data + no_data_timeframe = var.health_no_data_timeframe + notify_audit = false + timeout_h = 0 + include_tags = true + require_full_window = false + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:beanstalk", "team:claranet", "created-by:terraform"], var.health_extra_tags) +} + +resource "datadog_monitor" "application_latency_p90" { + count = var.application_latency_p90_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Beanstalk Application latency p90 {{#is_alert}}{{{comparator}}} {{threshold}}sec ({{value}}sec){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}sec ({{value}}sec){{/is_warning}}" + message = coalesce(var.application_latency_p90_message, var.message) + type = "metric alert" + + query = <= ${var.application_latency_p90_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.application_latency_p90_threshold_critical + warning = var.application_latency_p90_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + require_full_window = false + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:beanstalk", "team:claranet", "created-by:terraform"], var.application_latency_p90_extra_tags) +} + +resource "datadog_monitor" "application_5xx_error_rate" { + count = var.application_5xx_error_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Beanstalk Application 5xx error rate {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.application_5xx_error_rate_message, var.message) + type = "query alert" + + query = < ${var.application_5xx_error_rate_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.application_5xx_error_rate_threshold_critical + warning = var.application_5xx_error_rate_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + require_full_window = false + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:beanstalk", "team:claranet", "created-by:terraform"], var.application_5xx_error_rate_extra_tags) +} + +resource "datadog_monitor" "root_filesystem_usage" { + count = var.root_filesystem_usage_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Beanstalk Instance root file system usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.root_filesystem_usage_message, var.message) + type = "metric alert" + + query = < ${var.root_filesystem_usage_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.root_filesystem_usage_threshold_critical + warning = var.root_filesystem_usage_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + timeout_h = var.root_filesystem_usage_timeout_h + include_tags = true + require_full_window = false + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:beanstalk", "team:claranet", "created-by:terraform"], var.root_filesystem_usage_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/beanstalk/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/beanstalk/outputs.tf new file mode 100755 index 0000000..ad6d3ed --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/beanstalk/outputs.tf @@ -0,0 +1,20 @@ +output "application_5xx_error_rate_id" { + description = "id for monitor application_5xx_error_rate" + value = datadog_monitor.application_5xx_error_rate.*.id +} + +output "application_latency_p90_id" { + description = "id for monitor application_latency_p90" + value = datadog_monitor.application_latency_p90.*.id +} + +output "health_id" { + description = "id for monitor health" + value = datadog_monitor.health.*.id +} + +output "root_filesystem_usage_id" { + description = "id for monitor root_filesystem_usage" + value = datadog_monitor.root_filesystem_usage.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/beanstalk/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/beanstalk/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/beanstalk/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/common/MANIFEST.txt b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/common/MANIFEST.txt new file mode 100755 index 0000000..3d83252 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/common/MANIFEST.txt @@ -0,0 +1 @@ +cloud-aws diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/common/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/common/README.md new file mode 100755 index 0000000..6e029a1 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/common/README.md @@ -0,0 +1,95 @@ +# CLOUD AWS ECS COMMON DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-ecs-common" { + source = "claranet/monitors/datadog//cloud/aws/ecs/common" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- ECS Service CPU Utilization High (disabled by default) +- ECS Service Memory Utilization High (disabled by default) +- ECS Service not healthy enough + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.service_cpu_utilization](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.service_memory_utilization](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.service_missing_tasks](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags](#input\_filter\_tags) | Tags used for filtering | `string` | `"*"` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [service\_cpu\_utilization\_enabled](#input\_service\_cpu\_utilization\_enabled) | Flag to enable Service CPU Utilization monitor | `string` | `"false"` | no | +| [service\_cpu\_utilization\_extra\_tags](#input\_service\_cpu\_utilization\_extra\_tags) | Extra tags for Service CPU Utilization monitor | `list(string)` | `[]` | no | +| [service\_cpu\_utilization\_message](#input\_service\_cpu\_utilization\_message) | Custom message for the Service CPU Utilization monitor | `string` | `""` | no | +| [service\_cpu\_utilization\_threshold\_critical](#input\_service\_cpu\_utilization\_threshold\_critical) | Critical threshold for the Service CPU Utilization monitor | `string` | `"90"` | no | +| [service\_cpu\_utilization\_threshold\_warning](#input\_service\_cpu\_utilization\_threshold\_warning) | Warning threshold for the Service CPU Utilization monitor | `string` | `"80"` | no | +| [service\_cpu\_utilization\_time\_aggregator](#input\_service\_cpu\_utilization\_time\_aggregator) | Monitor aggregator for Service CPU Utilization [available values: min, max or avg] | `string` | `"min"` | no | +| [service\_cpu\_utilization\_timeframe](#input\_service\_cpu\_utilization\_timeframe) | Timeframe for the Service CPU Utilization monitor | `string` | `"last_5m"` | no | +| [service\_memory\_utilization\_enabled](#input\_service\_memory\_utilization\_enabled) | Flag to enable Service Memory Utilization monitor | `string` | `"false"` | no | +| [service\_memory\_utilization\_extra\_tags](#input\_service\_memory\_utilization\_extra\_tags) | Extra tags for Service Memory Utilization monitor | `list(string)` | `[]` | no | +| [service\_memory\_utilization\_message](#input\_service\_memory\_utilization\_message) | Custom message for the Service Memory Utilization monitor | `string` | `""` | no | +| [service\_memory\_utilization\_threshold\_critical](#input\_service\_memory\_utilization\_threshold\_critical) | Critical threshold for the Service Memory Utilization monitor | `string` | `90` | no | +| [service\_memory\_utilization\_threshold\_warning](#input\_service\_memory\_utilization\_threshold\_warning) | Warning threshold for the Service Memory Utilization monitor | `string` | `85` | no | +| [service\_memory\_utilization\_time\_aggregator](#input\_service\_memory\_utilization\_time\_aggregator) | Monitor aggregator for Service Memory Utilization [available values: min, max or avg] | `string` | `"min"` | no | +| [service\_memory\_utilization\_timeframe](#input\_service\_memory\_utilization\_timeframe) | Timeframe for the Service Memory Utilization monitor | `string` | `"last_5m"` | no | +| [service\_missing\_tasks\_enabled](#input\_service\_missing\_tasks\_enabled) | Flag to enable Service Missing Tasks monitor | `string` | `"true"` | no | +| [service\_missing\_tasks\_extra\_tags](#input\_service\_missing\_tasks\_extra\_tags) | Extra tags for Service Missing Tasks monitor | `list(string)` | `[]` | no | +| [service\_missing\_tasks\_message](#input\_service\_missing\_tasks\_message) | Custom message for the Service Missing Tasks monitor | `string` | `""` | no | +| [service\_missing\_tasks\_threshold\_critical](#input\_service\_missing\_tasks\_threshold\_critical) | Critical threshold for the Service Missing Tasks monitor | `string` | `60` | no | +| [service\_missing\_tasks\_threshold\_warning](#input\_service\_missing\_tasks\_threshold\_warning) | Warning threshold for the Service Missing Tasks monitor | `string` | `80` | no | +| [service\_missing\_tasks\_time\_aggregator](#input\_service\_missing\_tasks\_time\_aggregator) | Monitor aggregator for Service Missing Tasks [available values: min, max or avg] | `string` | `"min"` | no | +| [service\_missing\_tasks\_timeframe](#input\_service\_missing\_tasks\_timeframe) | Timeframe for the Service Missing Tasks monitor | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [service\_cpu\_utilization\_id](#output\_service\_cpu\_utilization\_id) | id for monitor service\_cpu\_utilization | +| [service\_memory\_utilization\_id](#output\_service\_memory\_utilization\_id) | id for monitor service\_memory\_utilization | +| [service\_missing\_tasks\_id](#output\_service\_missing\_tasks\_id) | id for monitor service\_missing\_tasks | +## Related documentation + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/common/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/common/inputs.tf new file mode 100755 index 0000000..226f12a --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/common/inputs.tf @@ -0,0 +1,186 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags" { + description = "Tags used for filtering" + default = "*" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# +# Service CPU Utilization +# +variable "service_cpu_utilization_enabled" { + description = "Flag to enable Service CPU Utilization monitor" + type = string + default = "false" +} + +variable "service_cpu_utilization_extra_tags" { + description = "Extra tags for Service CPU Utilization monitor" + type = list(string) + default = [] +} + +variable "service_cpu_utilization_message" { + description = "Custom message for the Service CPU Utilization monitor" + type = string + default = "" +} + +variable "service_cpu_utilization_timeframe" { + description = "Timeframe for the Service CPU Utilization monitor" + type = string + default = "last_5m" +} + +variable "service_cpu_utilization_time_aggregator" { + description = "Monitor aggregator for Service CPU Utilization [available values: min, max or avg]" + type = string + default = "min" +} + +variable "service_cpu_utilization_threshold_critical" { + description = "Critical threshold for the Service CPU Utilization monitor" + type = string + default = "90" +} + +variable "service_cpu_utilization_threshold_warning" { + description = "Warning threshold for the Service CPU Utilization monitor" + type = string + default = "80" +} + +# +# Service Memory Utilization +# +variable "service_memory_utilization_enabled" { + description = "Flag to enable Service Memory Utilization monitor" + type = string + default = "false" +} + +variable "service_memory_utilization_extra_tags" { + description = "Extra tags for Service Memory Utilization monitor" + type = list(string) + default = [] +} + +variable "service_memory_utilization_message" { + description = "Custom message for the Service Memory Utilization monitor" + type = string + default = "" +} + +variable "service_memory_utilization_timeframe" { + description = "Timeframe for the Service Memory Utilization monitor" + type = string + default = "last_5m" +} + +variable "service_memory_utilization_time_aggregator" { + description = "Monitor aggregator for Service Memory Utilization [available values: min, max or avg]" + type = string + default = "min" +} + +variable "service_memory_utilization_threshold_critical" { + description = "Critical threshold for the Service Memory Utilization monitor" + type = string + default = 90 +} + +variable "service_memory_utilization_threshold_warning" { + description = "Warning threshold for the Service Memory Utilization monitor" + type = string + default = 85 +} + +# +# Service Missing tasks +# +variable "service_missing_tasks_enabled" { + description = "Flag to enable Service Missing Tasks monitor" + type = string + default = "true" +} + +variable "service_missing_tasks_extra_tags" { + description = "Extra tags for Service Missing Tasks monitor" + type = list(string) + default = [] +} + +variable "service_missing_tasks_message" { + description = "Custom message for the Service Missing Tasks monitor" + type = string + default = "" +} + +variable "service_missing_tasks_timeframe" { + description = "Timeframe for the Service Missing Tasks monitor" + type = string + default = "last_5m" +} + +variable "service_missing_tasks_time_aggregator" { + description = "Monitor aggregator for Service Missing Tasks [available values: min, max or avg]" + type = string + default = "min" +} + +variable "service_missing_tasks_threshold_critical" { + description = "Critical threshold for the Service Missing Tasks monitor" + type = string + default = 60 +} + +variable "service_missing_tasks_threshold_warning" { + description = "Warning threshold for the Service Missing Tasks monitor" + type = string + default = 80 +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/common/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/common/modules.tf new file mode 100755 index 0000000..cdaf5f1 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/common/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../../common/filter-tags" + + environment = var.environment + resource = "aws_ecs" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/common/monitors-ecs-common.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/common/monitors-ecs-common.tf new file mode 100755 index 0000000..2607570 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/common/monitors-ecs-common.tf @@ -0,0 +1,92 @@ +# Monitors related to services +resource "datadog_monitor" "service_cpu_utilization" { + count = var.service_cpu_utilization_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ECS Service CPU Utilization High {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.service_cpu_utilization_message, var.message) + type = "metric alert" + + query = < ${var.service_cpu_utilization_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.service_cpu_utilization_threshold_critical + warning = var.service_cpu_utilization_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:ecs", "team:claranet", "created-by:terraform", "category:service"], var.service_cpu_utilization_extra_tags) +} + +resource "datadog_monitor" "service_memory_utilization" { + count = var.service_memory_utilization_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ECS Service Memory Utilization High {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.service_memory_utilization_message, var.message) + type = "metric alert" + + query = < ${var.service_memory_utilization_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.service_memory_utilization_threshold_critical + warning = var.service_memory_utilization_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:ecs", "team:claranet", "created-by:terraform", "category:service"], var.service_memory_utilization_extra_tags) +} + +resource "datadog_monitor" "service_missing_tasks" { + count = var.service_missing_tasks_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ECS Service not healthy enough {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.service_missing_tasks_message, var.message) + type = "metric alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cluster_cpu_utilization](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.cluster_memory_reservation](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ecs_agent_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [agent\_status\_enabled](#input\_agent\_status\_enabled) | Flag to enable Agent Status monitor | `string` | `"true"` | no | +| [agent\_status\_extra\_tags](#input\_agent\_status\_extra\_tags) | Extra tags for Agent Status monitor | `list(string)` | `[]` | no | +| [agent\_status\_message](#input\_agent\_status\_message) | Custom message for the Agent Status monitor | `string` | `""` | no | +| [agent\_status\_no\_data\_timeframe](#input\_agent\_status\_no\_data\_timeframe) | Agent status does not respond monitor no data timeframe | `string` | `10` | no | +| [agent\_status\_threshold\_warning](#input\_agent\_status\_threshold\_warning) | Warning threshold for the Agent Status monitor | `string` | `3` | no | +| [cluster\_cpu\_utilization\_enabled](#input\_cluster\_cpu\_utilization\_enabled) | Flag to enable Cluster CPU utilization monitor | `string` | `"false"` | no | +| [cluster\_cpu\_utilization\_extra\_tags](#input\_cluster\_cpu\_utilization\_extra\_tags) | Extra tags for Cluster CPU utilization monitor | `list(string)` | `[]` | no | +| [cluster\_cpu\_utilization\_message](#input\_cluster\_cpu\_utilization\_message) | Custom message for the Cluster CPU Utilization monitor | `string` | `""` | no | +| [cluster\_cpu\_utilization\_threshold\_critical](#input\_cluster\_cpu\_utilization\_threshold\_critical) | Critical threshold for the Cluster CPU Utilization monitor | `string` | `90` | no | +| [cluster\_cpu\_utilization\_threshold\_warning](#input\_cluster\_cpu\_utilization\_threshold\_warning) | Warning threshold for the Cluster CPU Utilization monitor | `string` | `85` | no | +| [cluster\_cpu\_utilization\_time\_aggregator](#input\_cluster\_cpu\_utilization\_time\_aggregator) | Monitor aggregator for Cluster CPU Utilization [available values: min, max or avg] | `string` | `"min"` | no | +| [cluster\_cpu\_utilization\_timeframe](#input\_cluster\_cpu\_utilization\_timeframe) | Timeframe for the Cluster CPU Utilization monitor | `string` | `"last_5m"` | no | +| [cluster\_memory\_reservation\_enabled](#input\_cluster\_memory\_reservation\_enabled) | Flag to enable Cluster memory reservation monitor | `string` | `"false"` | no | +| [cluster\_memory\_reservation\_extra\_tags](#input\_cluster\_memory\_reservation\_extra\_tags) | Extra tags for Cluster Memory Reservation monitor | `list(string)` | `[]` | no | +| [cluster\_memory\_reservation\_message](#input\_cluster\_memory\_reservation\_message) | Custom message for the Cluster Memory Reservation monitor | `string` | `""` | no | +| [cluster\_memory\_reservation\_threshold\_critical](#input\_cluster\_memory\_reservation\_threshold\_critical) | Critical threshold for the Cluster Memory Reservation monitor | `string` | `90` | no | +| [cluster\_memory\_reservation\_threshold\_warning](#input\_cluster\_memory\_reservation\_threshold\_warning) | Warning threshold for the Cluster Memory Reservation monitor | `string` | `85` | no | +| [cluster\_memory\_reservation\_time\_aggregator](#input\_cluster\_memory\_reservation\_time\_aggregator) | Monitor aggregator for Cluster Memory Reservation [available values: min, max or avg] | `string` | `"min"` | no | +| [cluster\_memory\_reservation\_timeframe](#input\_cluster\_memory\_reservation\_timeframe) | Timeframe for the Cluster Memory Reservation monitor | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cluster\_cpu\_utilization\_id](#output\_cluster\_cpu\_utilization\_id) | id for monitor cluster\_cpu\_utilization | +| [cluster\_memory\_reservation\_id](#output\_cluster\_memory\_reservation\_id) | id for monitor cluster\_memory\_reservation | +| [ecs\_agent\_status\_id](#output\_ecs\_agent\_status\_id) | id for monitor ecs\_agent\_status | +## Related documentation + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/ec2-cluster/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/ec2-cluster/inputs.tf new file mode 100755 index 0000000..c9910f8 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/ec2-cluster/inputs.tf @@ -0,0 +1,170 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# +# Agent Status +# +variable "agent_status_enabled" { + description = "Flag to enable Agent Status monitor" + type = string + default = "true" +} + +variable "agent_status_extra_tags" { + description = "Extra tags for Agent Status monitor" + type = list(string) + default = [] +} + +variable "agent_status_message" { + description = "Custom message for the Agent Status monitor" + type = string + default = "" +} + +variable "agent_status_threshold_warning" { + description = "Warning threshold for the Agent Status monitor" + type = string + default = 3 +} + +variable "agent_status_no_data_timeframe" { + description = "Agent status does not respond monitor no data timeframe" + type = string + default = 10 +} + +# +# Cluster CPU Utilization +# +variable "cluster_cpu_utilization_enabled" { + description = "Flag to enable Cluster CPU utilization monitor" + type = string + default = "false" +} + +variable "cluster_cpu_utilization_extra_tags" { + description = "Extra tags for Cluster CPU utilization monitor" + type = list(string) + default = [] +} + +variable "cluster_cpu_utilization_message" { + description = "Custom message for the Cluster CPU Utilization monitor" + type = string + default = "" +} + +variable "cluster_cpu_utilization_time_aggregator" { + description = "Monitor aggregator for Cluster CPU Utilization [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cluster_cpu_utilization_timeframe" { + description = "Timeframe for the Cluster CPU Utilization monitor" + type = string + default = "last_5m" +} + +variable "cluster_cpu_utilization_threshold_critical" { + description = "Critical threshold for the Cluster CPU Utilization monitor" + type = string + default = 90 +} + +variable "cluster_cpu_utilization_threshold_warning" { + description = "Warning threshold for the Cluster CPU Utilization monitor" + type = string + default = 85 +} + + +# +# Cluster Memory Reservation +# +variable "cluster_memory_reservation_enabled" { + description = "Flag to enable Cluster memory reservation monitor" + type = string + default = "false" +} + +variable "cluster_memory_reservation_extra_tags" { + description = "Extra tags for Cluster Memory Reservation monitor" + type = list(string) + default = [] +} + +variable "cluster_memory_reservation_message" { + description = "Custom message for the Cluster Memory Reservation monitor" + type = string + default = "" +} + +variable "cluster_memory_reservation_time_aggregator" { + description = "Monitor aggregator for Cluster Memory Reservation [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cluster_memory_reservation_timeframe" { + description = "Timeframe for the Cluster Memory Reservation monitor" + type = string + default = "last_5m" +} + +variable "cluster_memory_reservation_threshold_critical" { + description = "Critical threshold for the Cluster Memory Reservation monitor" + type = string + default = 90 +} + +variable "cluster_memory_reservation_threshold_warning" { + description = "Warning threshold for the Cluster Memory Reservation monitor" + type = string + default = 85 +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/ec2-cluster/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/ec2-cluster/modules.tf new file mode 100755 index 0000000..cdaf5f1 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/ec2-cluster/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../../common/filter-tags" + + environment = var.environment + resource = "aws_ecs" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/ec2-cluster/monitors-ecs-ec2-cluster.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/ec2-cluster/monitors-ecs-ec2-cluster.tf new file mode 100755 index 0000000..2766414 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/ec2-cluster/monitors-ecs-ec2-cluster.tf @@ -0,0 +1,93 @@ +# Monitors related to ECS Cluster +resource "datadog_monitor" "ecs_agent_status" { + count = var.agent_status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ECS Agent disconnected {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.agent_status_message, var.message) + type = "service check" + + query = < ${var.cluster_cpu_utilization_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.cluster_cpu_utilization_threshold_critical + warning = var.cluster_cpu_utilization_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:ecs", "team:claranet", "created-by:terraform", "category:cluster"], var.cluster_cpu_utilization_extra_tags) + +} + +resource "datadog_monitor" "cluster_memory_reservation" { + count = var.cluster_memory_reservation_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ECS Cluster Memory Reservation High {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cluster_memory_reservation_message, var.message) + type = "metric alert" + + query = < ${var.cluster_memory_reservation_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.cluster_memory_reservation_threshold_critical + warning = var.cluster_memory_reservation_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:ecs", "team:claranet", "created-by:terraform", "category:cluster"], var.cluster_memory_reservation_extra_tags) +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/ec2-cluster/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/ec2-cluster/outputs.tf new file mode 100755 index 0000000..7d7b544 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/ec2-cluster/outputs.tf @@ -0,0 +1,15 @@ +output "cluster_cpu_utilization_id" { + description = "id for monitor cluster_cpu_utilization" + value = datadog_monitor.cluster_cpu_utilization.*.id +} + +output "cluster_memory_reservation_id" { + description = "id for monitor cluster_memory_reservation" + value = datadog_monitor.cluster_memory_reservation.*.id +} + +output "ecs_agent_status_id" { + description = "id for monitor ecs_agent_status" + value = datadog_monitor.ecs_agent_status.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/ec2-cluster/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/ec2-cluster/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/ec2-cluster/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/fargate/MANIFEST.txt b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/fargate/MANIFEST.txt new file mode 100755 index 0000000..3d83252 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/fargate/MANIFEST.txt @@ -0,0 +1 @@ +cloud-aws diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/fargate/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/fargate/README.md new file mode 100755 index 0000000..28f3ce0 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/fargate/README.md @@ -0,0 +1,99 @@ +# CLOUD AWS ECS FARGATE DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-ecs-fargate" { + source = "claranet/monitors/datadog//cloud/aws/ecs/fargate" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Fargate CPU Utilization High (disabled by default) +- Fargate memory Utilization High (disabled by default) +- Fargate service does not respond. + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cpu_utilization](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.memory_utilization](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.service_check](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_utilization\_enabled](#input\_cpu\_utilization\_enabled) | Flag to enable monitor | `string` | `"false"` | no | +| [cpu\_utilization\_extra\_tags](#input\_cpu\_utilization\_extra\_tags) | Extra tags for the monitor | `list(string)` | `[]` | no | +| [cpu\_utilization\_message](#input\_cpu\_utilization\_message) | Custom message for the monitor | `string` | `""` | no | +| [cpu\_utilization\_threshold\_critical](#input\_cpu\_utilization\_threshold\_critical) | Critical threshold for the monitor | `string` | `90` | no | +| [cpu\_utilization\_threshold\_warning](#input\_cpu\_utilization\_threshold\_warning) | Warning threshold for the monitor | `string` | `85` | no | +| [cpu\_utilization\_time\_aggregator](#input\_cpu\_utilization\_time\_aggregator) | Monitor aggregator (min, max or avg) | `string` | `"min"` | no | +| [cpu\_utilization\_timeframe](#input\_cpu\_utilization\_timeframe) | Timeframe for the monitor | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `bool` | `true` | no | +| [memory\_utilization\_enabled](#input\_memory\_utilization\_enabled) | Flag to enable Fargate Memory utilization monitor | `string` | `"false"` | no | +| [memory\_utilization\_extra\_tags](#input\_memory\_utilization\_extra\_tags) | Extra tags for Fargate Memory utilization monitor | `list(string)` | `[]` | no | +| [memory\_utilization\_message](#input\_memory\_utilization\_message) | Custom message for the Fargate Memory Utilization monitor | `string` | `""` | no | +| [memory\_utilization\_threshold\_critical](#input\_memory\_utilization\_threshold\_critical) | Critical threshold for the Fargate Memory Utilization monitor | `string` | `90` | no | +| [memory\_utilization\_threshold\_warning](#input\_memory\_utilization\_threshold\_warning) | Warning threshold for the Fargate Memory Utilization monitor | `string` | `85` | no | +| [memory\_utilization\_time\_aggregator](#input\_memory\_utilization\_time\_aggregator) | Monitor aggregator for Fargate Memory Utilization [available values: min, max or avg] | `string` | `"min"` | no | +| [memory\_utilization\_timeframe](#input\_memory\_utilization\_timeframe) | Timeframe for the Fargate Memory Utilization monitor | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `string` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [service\_check\_enabled](#input\_service\_check\_enabled) | Flag to enable monitor | `bool` | `true` | no | +| [service\_check\_extra\_tags](#input\_service\_check\_extra\_tags) | Extra tags for the monitor | `list(string)` | `[]` | no | +| [service\_check\_message](#input\_service\_check\_message) | Custom message for the monitor | `string` | `""` | no | +| [service\_check\_no\_data\_timeframe](#input\_service\_check\_no\_data\_timeframe) | No data timeframe in minutes | `number` | `10` | no | +| [service\_check\_threshold\_warning](#input\_service\_check\_threshold\_warning) | Warning threshold | `number` | `3` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cpu\_utilization\_id](#output\_cpu\_utilization\_id) | id for monitor cpu\_utilization | +| [memory\_utilization\_id](#output\_memory\_utilization\_id) | id for monitor memory\_utilization | +| [service\_check\_id](#output\_service\_check\_id) | id for monitor service\_check | +## Related documentation + +[Official DataDog documentation on ECS Fargate](https://docs.datadoghq.com/integrations/ecs_fargate/) + +### Specific configuration due to agent limitations + +CPU & memory monitors will be usable only when deploying datadog agent as a sidecar in task definitions. + +In order to avoid clutter on monitors, datadog agent & ECS internal containers are always excluded from filtering to be on par with Kubernetes way of work. A bug is [currently opened](https://github.com/DataDog/datadog-agent/issues/2722) on agent repository on this matter. diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/fargate/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/fargate/inputs.tf new file mode 100755 index 0000000..97be59f --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/fargate/inputs.tf @@ -0,0 +1,169 @@ +# Generics + +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "message" { + type = string + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + type = number + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + type = number + default = 300 +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + type = bool + default = true +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + type = bool + default = true +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + type = string + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + type = string + default = "" +} + +# Service checks +variable "service_check_enabled" { + type = bool + description = "Flag to enable monitor " + default = true +} + +variable "service_check_message" { + type = string + description = "Custom message for the monitor" + default = "" +} + +variable "service_check_extra_tags" { + type = list(string) + description = "Extra tags for the monitor" + default = [] +} + +variable "service_check_threshold_warning" { + type = number + description = "Warning threshold" + default = 3 +} + +variable "service_check_no_data_timeframe" { + type = number + description = "No data timeframe in minutes" + default = 10 +} + +# CPU utilization +variable "cpu_utilization_enabled" { + description = "Flag to enable monitor" + type = string + default = "false" +} + +variable "cpu_utilization_message" { + description = "Custom message for the monitor" + type = string + default = "" +} + +variable "cpu_utilization_time_aggregator" { + description = "Monitor aggregator (min, max or avg)" + type = string + default = "min" +} + +variable "cpu_utilization_timeframe" { + description = "Timeframe for the monitor" + type = string + default = "last_5m" +} + +variable "cpu_utilization_threshold_critical" { + description = "Critical threshold for the monitor" + type = string + default = 90 +} + +variable "cpu_utilization_threshold_warning" { + description = "Warning threshold for the monitor" + type = string + default = 85 +} + +variable "cpu_utilization_extra_tags" { + description = "Extra tags for the monitor" + type = list(string) + default = [] +} + +# Memory usage +variable "memory_utilization_enabled" { + description = "Flag to enable Fargate Memory utilization monitor" + type = string + default = "false" +} + +variable "memory_utilization_extra_tags" { + description = "Extra tags for Fargate Memory utilization monitor" + type = list(string) + default = [] +} + +variable "memory_utilization_message" { + description = "Custom message for the Fargate Memory Utilization monitor" + type = string + default = "" +} + +variable "memory_utilization_time_aggregator" { + description = "Monitor aggregator for Fargate Memory Utilization [available values: min, max or avg]" + type = string + default = "min" +} + +variable "memory_utilization_timeframe" { + description = "Timeframe for the Fargate Memory Utilization monitor" + type = string + default = "last_5m" +} + +variable "memory_utilization_threshold_critical" { + description = "Critical threshold for the Fargate Memory Utilization monitor" + type = string + default = 90 +} + +variable "memory_utilization_threshold_warning" { + description = "Warning threshold for the Fargate Memory Utilization monitor" + type = string + default = 85 +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/fargate/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/fargate/modules.tf new file mode 100755 index 0000000..6eaf996 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/fargate/modules.tf @@ -0,0 +1,14 @@ +module "filter-tags" { + + source = "../../../../common/filter-tags" + + environment = var.environment + resource = "aws_ecs" + extra_tags_excluded = [ + "ecs_container_name:datadog-agent", + "ecs_container_name:_internal_ecs_pause" + ] + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/fargate/monitors-ecs-fargate.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/fargate/monitors-ecs-fargate.tf new file mode 100755 index 0000000..d8d58fb --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/fargate/monitors-ecs-fargate.tf @@ -0,0 +1,97 @@ +# Service check + +resource "datadog_monitor" "service_check" { + count = var.service_check_enabled ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Fargate service does not respond." + message = coalesce(var.service_check_message, var.message) + type = "service check" + + query = < ${var.cpu_utilization_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.cpu_utilization_threshold_critical + warning = var.cpu_utilization_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + require_full_window = true + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:ecs_fargate", "team:claranet", "created-by:terraform"], var.cpu_utilization_extra_tags) + +} + +resource "datadog_monitor" "memory_utilization" { + count = var.memory_utilization_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Fargate memory Utilization High {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.memory_utilization_message, var.message) + type = "metric alert" + + query = < ${var.memory_utilization_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.memory_utilization_threshold_critical + warning = var.memory_utilization_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + require_full_window = true + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:ecs_fargate", "team:claranet", "created-by:terraform"], var.memory_utilization_extra_tags) + +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/fargate/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/fargate/outputs.tf new file mode 100755 index 0000000..6331f44 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/fargate/outputs.tf @@ -0,0 +1,15 @@ +output "cpu_utilization_id" { + description = "id for monitor cpu_utilization" + value = datadog_monitor.cpu_utilization.*.id +} + +output "memory_utilization_id" { + description = "id for monitor memory_utilization" + value = datadog_monitor.memory_utilization.*.id +} + +output "service_check_id" { + description = "id for monitor service_check" + value = datadog_monitor.service_check.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/fargate/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/fargate/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/ecs/fargate/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/common/MANIFEST.txt b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/common/MANIFEST.txt new file mode 100755 index 0000000..3d83252 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/common/MANIFEST.txt @@ -0,0 +1 @@ +cloud-aws diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/common/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/common/README.md new file mode 100755 index 0000000..c7b8a57 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/common/README.md @@ -0,0 +1,122 @@ +# CLOUD AWS ELASTICACHE COMMON DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-elasticache-common" { + source = "claranet/monitors/datadog//cloud/aws/elasticache/common" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Elasticache connections +- Elasticache eviction +- Elasticache evictions is growing +- Elasticache free memory +- Elasticache max connections reached +- Elasticache swap + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.elasticache_eviction](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.elasticache_eviction_growing](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.elasticache_free_memory](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.elasticache_max_connection](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.elasticache_no_connection](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.elasticache_swap](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [elasticache\_max\_connection\_no\_data\_timeframe](#input\_elasticache\_max\_connection\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [environment](#input\_environment) | Infrastructure Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [eviction\_enabled](#input\_eviction\_enabled) | Flag to enable Elasticache eviction monitor | `string` | `"true"` | no | +| [eviction\_extra\_tags](#input\_eviction\_extra\_tags) | Extra tags for Elasticache eviction monitor | `list(string)` | `[]` | no | +| [eviction\_growing\_condition\_timeframe](#input\_eviction\_growing\_condition\_timeframe) | Monitor condition timeframe for Elasticache eviction growing [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [eviction\_growing\_enabled](#input\_eviction\_growing\_enabled) | Flag to enable Elasticache eviction growing monitor | `string` | `"true"` | no | +| [eviction\_growing\_extra\_tags](#input\_eviction\_growing\_extra\_tags) | Extra tags for Elasticache eviction growing monitor | `list(string)` | `[]` | no | +| [eviction\_growing\_message](#input\_eviction\_growing\_message) | Custom message for Elasticache eviction growing monitor | `string` | `""` | no | +| [eviction\_growing\_threshold\_critical](#input\_eviction\_growing\_threshold\_critical) | Elasticache eviction growing critical threshold in percentage | `string` | `30` | no | +| [eviction\_growing\_threshold\_warning](#input\_eviction\_growing\_threshold\_warning) | Elasticache eviction growing warning threshold in percentage | `string` | `10` | no | +| [eviction\_growing\_timeframe](#input\_eviction\_growing\_timeframe) | Monitor timeframe for Elasticache eviction growing [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [eviction\_message](#input\_eviction\_message) | Custom message for Elasticache eviction monitor | `string` | `""` | no | +| [eviction\_threshold\_critical](#input\_eviction\_threshold\_critical) | Elasticache free memory critical threshold in percentage | `string` | `30` | no | +| [eviction\_threshold\_warning](#input\_eviction\_threshold\_warning) | Elasticache free memory warning threshold in percentage | `string` | `0` | no | +| [eviction\_timeframe](#input\_eviction\_timeframe) | Monitor timeframe for Elasticache eviction [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [free\_memory\_condition\_timeframe](#input\_free\_memory\_condition\_timeframe) | Monitor condition timeframe for Elasticache free memory [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [free\_memory\_enabled](#input\_free\_memory\_enabled) | Flag to enable Elasticache free memory monitor | `string` | `"true"` | no | +| [free\_memory\_extra\_tags](#input\_free\_memory\_extra\_tags) | Extra tags for Elasticache free memory monitor | `list(string)` | `[]` | no | +| [free\_memory\_message](#input\_free\_memory\_message) | Custom message for Elasticache free memory monitor | `string` | `""` | no | +| [free\_memory\_threshold\_critical](#input\_free\_memory\_threshold\_critical) | Elasticache free memory critical threshold in percentage | `string` | `-70` | no | +| [free\_memory\_threshold\_warning](#input\_free\_memory\_threshold\_warning) | Elasticache free memory warning threshold in percentage | `string` | `-50` | no | +| [free\_memory\_timeframe](#input\_free\_memory\_timeframe) | Monitor timeframe for Elasticache free memory [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [max\_connection\_enabled](#input\_max\_connection\_enabled) | Flag to enable Elasticache max connection monitor | `string` | `"true"` | no | +| [max\_connection\_extra\_tags](#input\_max\_connection\_extra\_tags) | Extra tags for Elasticache max connection monitor | `list(string)` | `[]` | no | +| [max\_connection\_message](#input\_max\_connection\_message) | Custom message for Elasticache max connection monitor | `string` | `""` | no | +| [max\_connection\_time\_aggregator](#input\_max\_connection\_time\_aggregator) | Monitor aggregator for Elasticache max connection [available values: min, max or avg] | `string` | `"max"` | no | +| [max\_connection\_timeframe](#input\_max\_connection\_timeframe) | Monitor timeframe for Elasticache max connection [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [no\_connection\_enabled](#input\_no\_connection\_enabled) | Flag to enable Elasticache no connection monitor | `string` | `"true"` | no | +| [no\_connection\_extra\_tags](#input\_no\_connection\_extra\_tags) | Extra tags for Elasticache no connection monitor | `list(string)` | `[]` | no | +| [no\_connection\_message](#input\_no\_connection\_message) | Custom message for Elasticache no connection monitor | `string` | `""` | no | +| [no\_connection\_time\_aggregator](#input\_no\_connection\_time\_aggregator) | Monitor aggregator for Elasticache no connection [available values: min, max or avg] | `string` | `"min"` | no | +| [no\_connection\_timeframe](#input\_no\_connection\_timeframe) | Monitor timeframe for Elasticache no connection [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [swap\_enabled](#input\_swap\_enabled) | Flag to enable Elasticache swap monitor | `string` | `"true"` | no | +| [swap\_extra\_tags](#input\_swap\_extra\_tags) | Extra tags for Elasticache swap monitor | `list(string)` | `[]` | no | +| [swap\_message](#input\_swap\_message) | Custom message for Elasticache swap monitor | `string` | `""` | no | +| [swap\_threshold\_critical](#input\_swap\_threshold\_critical) | Elasticache swap critical threshold in bytes | `string` | `50000000` | no | +| [swap\_threshold\_warning](#input\_swap\_threshold\_warning) | Elasticache swap warning threshold in bytes | `string` | `0` | no | +| [swap\_time\_aggregator](#input\_swap\_time\_aggregator) | Monitor aggregator for Elasticache memcached swap [available values: min, max or avg] | `string` | `"min"` | no | +| [swap\_timeframe](#input\_swap\_timeframe) | Monitor timeframe for Elasticache swap [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [elasticache\_eviction\_growing\_id](#output\_elasticache\_eviction\_growing\_id) | id for monitor elasticache\_eviction\_growing | +| [elasticache\_eviction\_id](#output\_elasticache\_eviction\_id) | id for monitor elasticache\_eviction | +| [elasticache\_free\_memory\_id](#output\_elasticache\_free\_memory\_id) | id for monitor elasticache\_free\_memory | +| [elasticache\_max\_connection\_id](#output\_elasticache\_max\_connection\_id) | id for monitor elasticache\_max\_connection | +| [elasticache\_no\_connection\_id](#output\_elasticache\_no\_connection\_id) | id for monitor elasticache\_no\_connection | +| [elasticache\_swap\_id](#output\_elasticache\_swap\_id) | id for monitor elasticache\_swap | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/amazon_elasticache/](https://docs.datadoghq.com/integrations/amazon_elasticache/) + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/common/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/common/inputs.tf new file mode 100755 index 0000000..75e9f5c --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/common/inputs.tf @@ -0,0 +1,276 @@ +# Global Terraform +variable "environment" { + description = "Infrastructure Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "elasticache_max_connection_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Elasticache specific + +variable "eviction_enabled" { + description = "Flag to enable Elasticache eviction monitor" + type = string + default = "true" +} + +variable "eviction_extra_tags" { + description = "Extra tags for Elasticache eviction monitor" + type = list(string) + default = [] +} + +variable "eviction_message" { + description = "Custom message for Elasticache eviction monitor" + type = string + default = "" +} + +variable "eviction_timeframe" { + description = "Monitor timeframe for Elasticache eviction [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "eviction_threshold_warning" { + description = "Elasticache free memory warning threshold in percentage" + type = string + default = 0 +} + +variable "eviction_threshold_critical" { + description = "Elasticache free memory critical threshold in percentage" + type = string + default = 30 +} + +variable "max_connection_enabled" { + description = "Flag to enable Elasticache max connection monitor" + type = string + default = "true" +} + +variable "max_connection_extra_tags" { + description = "Extra tags for Elasticache max connection monitor" + type = list(string) + default = [] +} + +variable "max_connection_message" { + description = "Custom message for Elasticache max connection monitor" + type = string + default = "" +} + +variable "max_connection_time_aggregator" { + description = "Monitor aggregator for Elasticache max connection [available values: min, max or avg]" + type = string + default = "max" +} + +variable "max_connection_timeframe" { + description = "Monitor timeframe for Elasticache max connection [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "no_connection_enabled" { + description = "Flag to enable Elasticache no connection monitor" + type = string + default = "true" +} + +variable "no_connection_extra_tags" { + description = "Extra tags for Elasticache no connection monitor" + type = list(string) + default = [] +} + +variable "no_connection_message" { + description = "Custom message for Elasticache no connection monitor" + type = string + default = "" +} + +variable "no_connection_time_aggregator" { + description = "Monitor aggregator for Elasticache no connection [available values: min, max or avg]" + type = string + default = "min" +} + +variable "no_connection_timeframe" { + description = "Monitor timeframe for Elasticache no connection [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "swap_enabled" { + description = "Flag to enable Elasticache swap monitor" + type = string + default = "true" +} + +variable "swap_extra_tags" { + description = "Extra tags for Elasticache swap monitor" + type = list(string) + default = [] +} + +variable "swap_message" { + description = "Custom message for Elasticache swap monitor" + type = string + default = "" +} + +variable "swap_time_aggregator" { + description = "Monitor aggregator for Elasticache memcached swap [available values: min, max or avg]" + type = string + default = "min" +} + +variable "swap_timeframe" { + description = "Monitor timeframe for Elasticache swap [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "swap_threshold_warning" { + description = "Elasticache swap warning threshold in bytes" + type = string + default = 0 +} + +variable "swap_threshold_critical" { + description = "Elasticache swap critical threshold in bytes" + type = string + default = 50000000 +} + +variable "free_memory_enabled" { + description = "Flag to enable Elasticache free memory monitor" + type = string + default = "true" +} + +variable "free_memory_extra_tags" { + description = "Extra tags for Elasticache free memory monitor" + type = list(string) + default = [] +} + +variable "free_memory_message" { + description = "Custom message for Elasticache free memory monitor" + type = string + default = "" +} + +variable "free_memory_condition_timeframe" { + description = "Monitor condition timeframe for Elasticache free memory [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "free_memory_timeframe" { + description = "Monitor timeframe for Elasticache free memory [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "free_memory_threshold_warning" { + description = "Elasticache free memory warning threshold in percentage" + type = string + default = -50 +} + +variable "free_memory_threshold_critical" { + description = "Elasticache free memory critical threshold in percentage" + type = string + default = -70 +} + +variable "eviction_growing_enabled" { + description = "Flag to enable Elasticache eviction growing monitor" + type = string + default = "true" +} + +variable "eviction_growing_extra_tags" { + description = "Extra tags for Elasticache eviction growing monitor" + type = list(string) + default = [] +} + +variable "eviction_growing_message" { + description = "Custom message for Elasticache eviction growing monitor" + type = string + default = "" +} + +variable "eviction_growing_condition_timeframe" { + description = "Monitor condition timeframe for Elasticache eviction growing [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "eviction_growing_timeframe" { + description = "Monitor timeframe for Elasticache eviction growing [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "eviction_growing_threshold_warning" { + description = "Elasticache eviction growing warning threshold in percentage" + type = string + default = 10 +} + +variable "eviction_growing_threshold_critical" { + description = "Elasticache eviction growing critical threshold in percentage" + type = string + default = 30 +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/common/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/common/modules.tf new file mode 100755 index 0000000..1b317be --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/common/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../../common/filter-tags" + + environment = var.environment + resource = "aws_elasticache" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/common/monitors-elasticache.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/common/monitors-elasticache.tf new file mode 100755 index 0000000..22154d4 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/common/monitors-elasticache.tf @@ -0,0 +1,171 @@ +resource "datadog_monitor" "elasticache_eviction" { + count = var.eviction_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticache eviction {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}" + message = coalesce(var.eviction_message, var.message) + type = "query alert" + + query = < ${var.eviction_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.eviction_threshold_warning + critical = var.eviction_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elasticache", "team:claranet", "created-by:terraform"], var.eviction_extra_tags) +} + +resource "datadog_monitor" "elasticache_max_connection" { + count = var.max_connection_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticache max connections reached {{#is_alert}}{{{comparator}}} {{threshold}} {{/is_alert}}" + message = coalesce(var.max_connection_message, var.message) + type = "query alert" + + query = <= 65000 +EOQ + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = var.notify_no_data + no_data_timeframe = var.elasticache_max_connection_no_data_timeframe + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elasticache", "team:claranet", "created-by:terraform"], var.max_connection_extra_tags) +} + +resource "datadog_monitor" "elasticache_no_connection" { + count = var.no_connection_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticache connections {{#is_alert}}{{{comparator}}} {{threshold}} {{/is_alert}}" + message = coalesce(var.no_connection_message, var.message) + type = "query alert" + + query = < ${var.swap_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.swap_threshold_warning + critical = var.swap_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elasticache", "team:claranet", "created-by:terraform"], var.swap_extra_tags) +} + +resource "datadog_monitor" "elasticache_free_memory" { + count = var.free_memory_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticache free memory {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.free_memory_message, var.message) + type = "query alert" + + query = < ${var.eviction_growing_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.eviction_growing_threshold_warning + critical = var.eviction_growing_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elasticache", "team:claranet", "created-by:terraform"], var.eviction_growing_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/common/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/common/outputs.tf new file mode 100755 index 0000000..cea5f6a --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/common/outputs.tf @@ -0,0 +1,30 @@ +output "elasticache_eviction_id" { + description = "id for monitor elasticache_eviction" + value = datadog_monitor.elasticache_eviction.*.id +} + +output "elasticache_eviction_growing_id" { + description = "id for monitor elasticache_eviction_growing" + value = datadog_monitor.elasticache_eviction_growing.*.id +} + +output "elasticache_free_memory_id" { + description = "id for monitor elasticache_free_memory" + value = datadog_monitor.elasticache_free_memory.*.id +} + +output "elasticache_max_connection_id" { + description = "id for monitor elasticache_max_connection" + value = datadog_monitor.elasticache_max_connection.*.id +} + +output "elasticache_no_connection_id" { + description = "id for monitor elasticache_no_connection" + value = datadog_monitor.elasticache_no_connection.*.id +} + +output "elasticache_swap_id" { + description = "id for monitor elasticache_swap" + value = datadog_monitor.elasticache_swap.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/common/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/common/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/common/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/memcached/MANIFEST.txt b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/memcached/MANIFEST.txt new file mode 100755 index 0000000..3d83252 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/memcached/MANIFEST.txt @@ -0,0 +1 @@ +cloud-aws diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/memcached/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/memcached/README.md new file mode 100755 index 0000000..078f471 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/memcached/README.md @@ -0,0 +1,91 @@ +# CLOUD AWS ELASTICACHE MEMCACHED DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-elasticache-memcached" { + source = "claranet/monitors/datadog//cloud/aws/elasticache/memcached" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Elasticache memcached cache hit ratio +- Elasticache memcached CPU + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.memcached_cpu_high](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.memcached_get_hits](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_high\_enabled](#input\_cpu\_high\_enabled) | Flag to enable Elasticache memcached cpu high monitor | `string` | `"true"` | no | +| [cpu\_high\_extra\_tags](#input\_cpu\_high\_extra\_tags) | Extra tags for Elasticache memcached cpu high monitor | `list(string)` | `[]` | no | +| [cpu\_high\_message](#input\_cpu\_high\_message) | Custom message for Elasticache memcached cpu high monitor | `string` | `""` | no | +| [cpu\_high\_threshold\_critical](#input\_cpu\_high\_threshold\_critical) | Elasticache memcached cpu high critical threshold in percentage | `string` | `90` | no | +| [cpu\_high\_threshold\_warning](#input\_cpu\_high\_threshold\_warning) | Elasticache memcached cpu high warning threshold in percentage | `string` | `75` | no | +| [cpu\_high\_time\_aggregator](#input\_cpu\_high\_time\_aggregator) | Monitor aggregator for Elasticache memcached cpu high [available values: min, max or avg] | `string` | `"min"` | no | +| [cpu\_high\_timeframe](#input\_cpu\_high\_timeframe) | Monitor timeframe for Elasticache memcached cpu high [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [environment](#input\_environment) | Infrastructure Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [get\_hits\_enabled](#input\_get\_hits\_enabled) | Flag to enable Elasticache memcached get hits monitor | `string` | `"true"` | no | +| [get\_hits\_extra\_tags](#input\_get\_hits\_extra\_tags) | Extra tags for Elasticache memcached get hits monitor | `list(string)` | `[]` | no | +| [get\_hits\_message](#input\_get\_hits\_message) | Custom message for Elasticache memcached get hits monitor | `string` | `""` | no | +| [get\_hits\_threshold\_critical](#input\_get\_hits\_threshold\_critical) | Elasticache memcached get hits critical threshold in percentage | `string` | `60` | no | +| [get\_hits\_threshold\_warning](#input\_get\_hits\_threshold\_warning) | Elasticache memcached get hits warning threshold in percentage | `string` | `80` | no | +| [get\_hits\_time\_aggregator](#input\_get\_hits\_time\_aggregator) | Monitor aggregator for Elasticache memcached get hits [available values: min, max or avg] | `string` | `"max"` | no | +| [get\_hits\_timeframe](#input\_get\_hits\_timeframe) | Monitor timeframe for Elasticache memcached get hits [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [memcached\_cpu\_high\_no\_data\_timeframe](#input\_memcached\_cpu\_high\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `30` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [memcached\_cpu\_high\_id](#output\_memcached\_cpu\_high\_id) | id for monitor memcached\_cpu\_high | +| [memcached\_get\_hits\_id](#output\_memcached\_get\_hits\_id) | id for monitor memcached\_get\_hits | +## Related documentation + +DataDog documentation: + +* [https://docs.datadoghq.com/integrations/amazon_elasticache/](https://docs.datadoghq.com/integrations/amazon_elasticache/) +* [https://www.datadoghq.com/blog/monitoring-elasticache-performance-metrics-with-redis-or-memcached/](https://www.datadoghq.com/blog/monitoring-elasticache-performance-metrics-with-redis-or-memcached/) + + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/memcached/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/memcached/inputs.tf new file mode 100755 index 0000000..d7ba1c9 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/memcached/inputs.tf @@ -0,0 +1,138 @@ +# Global Terraform +variable "environment" { + description = "Infrastructure Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "memcached_cpu_high_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 30 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Memcached specific + +variable "get_hits_enabled" { + description = "Flag to enable Elasticache memcached get hits monitor" + type = string + default = "true" +} + +variable "get_hits_extra_tags" { + description = "Extra tags for Elasticache memcached get hits monitor" + type = list(string) + default = [] +} + +variable "get_hits_message" { + description = "Custom message for Elasticache memcached get hits monitor" + type = string + default = "" +} + +variable "get_hits_time_aggregator" { + description = "Monitor aggregator for Elasticache memcached get hits [available values: min, max or avg]" + type = string + default = "max" +} + +variable "get_hits_timeframe" { + description = "Monitor timeframe for Elasticache memcached get hits [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "get_hits_threshold_warning" { + description = "Elasticache memcached get hits warning threshold in percentage" + type = string + default = 80 +} + +variable "get_hits_threshold_critical" { + description = "Elasticache memcached get hits critical threshold in percentage" + type = string + default = 60 +} + +variable "cpu_high_enabled" { + description = "Flag to enable Elasticache memcached cpu high monitor" + type = string + default = "true" +} + +variable "cpu_high_extra_tags" { + description = "Extra tags for Elasticache memcached cpu high monitor" + type = list(string) + default = [] +} + +variable "cpu_high_message" { + description = "Custom message for Elasticache memcached cpu high monitor" + type = string + default = "" +} + +variable "cpu_high_time_aggregator" { + description = "Monitor aggregator for Elasticache memcached cpu high [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cpu_high_timeframe" { + description = "Monitor timeframe for Elasticache memcached cpu high [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "cpu_high_threshold_warning" { + description = "Elasticache memcached cpu high warning threshold in percentage" + type = string + default = 75 +} + +variable "cpu_high_threshold_critical" { + description = "Elasticache memcached cpu high critical threshold in percentage" + type = string + default = 90 +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/memcached/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/memcached/modules.tf new file mode 100755 index 0000000..1b317be --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/memcached/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../../common/filter-tags" + + environment = var.environment + resource = "aws_elasticache" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/memcached/monitors-memcached.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/memcached/monitors-memcached.tf new file mode 100755 index 0000000..9bb1a4c --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/memcached/monitors-memcached.tf @@ -0,0 +1,63 @@ +resource "datadog_monitor" "memcached_get_hits" { + count = var.get_hits_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticache memcached cache hit ratio {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.get_hits_message, var.message) + type = "query alert" + + query = < ${var.cpu_high_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.cpu_high_threshold_warning + critical = var.cpu_high_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = var.notify_no_data + no_data_timeframe = var.memcached_cpu_high_no_data_timeframe + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elasticache-memcached", "team:claranet", "created-by:terraform", "engine:memcached"], var.cpu_high_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/memcached/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/memcached/outputs.tf new file mode 100755 index 0000000..a5a89e3 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/memcached/outputs.tf @@ -0,0 +1,10 @@ +output "memcached_cpu_high_id" { + description = "id for monitor memcached_cpu_high" + value = datadog_monitor.memcached_cpu_high.*.id +} + +output "memcached_get_hits_id" { + description = "id for monitor memcached_get_hits" + value = datadog_monitor.memcached_get_hits.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/memcached/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/memcached/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/memcached/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/redis/MANIFEST.txt b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/redis/MANIFEST.txt new file mode 100755 index 0000000..3d83252 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/redis/MANIFEST.txt @@ -0,0 +1 @@ +cloud-aws diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/redis/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/redis/README.md new file mode 100755 index 0000000..07c2bd0 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/redis/README.md @@ -0,0 +1,106 @@ +# CLOUD AWS ELASTICACHE REDIS DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-elasticache-redis" { + source = "claranet/monitors/datadog//cloud/aws/elasticache/redis" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Elasticache redis cache hit ratio +- Elasticache redis CPU +- Elasticache redis is receiving no commands +- Elasticache redis replication lag + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.redis_cache_hits](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.redis_commands](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.redis_cpu_high](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.redis_replication_lag](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cache\_hits\_enabled](#input\_cache\_hits\_enabled) | Flag to enable Elasticache redis cache hits monitor | `string` | `"true"` | no | +| [cache\_hits\_extra\_tags](#input\_cache\_hits\_extra\_tags) | Extra tags for Elasticache redis cache hits monitor | `list(string)` | `[]` | no | +| [cache\_hits\_message](#input\_cache\_hits\_message) | Custom message for Elasticache redis cache hits monitor | `string` | `""` | no | +| [cache\_hits\_threshold\_critical](#input\_cache\_hits\_threshold\_critical) | Elasticache redis cache hits critical threshold in percentage | `string` | `60` | no | +| [cache\_hits\_threshold\_warning](#input\_cache\_hits\_threshold\_warning) | Elasticache redis cache hits warning threshold in percentage | `string` | `80` | no | +| [cache\_hits\_time\_aggregator](#input\_cache\_hits\_time\_aggregator) | Monitor aggregator for Elasticache redis cache hits [available values: min, max or avg] | `string` | `"max"` | no | +| [cache\_hits\_timeframe](#input\_cache\_hits\_timeframe) | Monitor timeframe for Elasticache redis cache hits [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [commands\_enabled](#input\_commands\_enabled) | Flag to enable Elasticache redis commands monitor | `string` | `"true"` | no | +| [commands\_extra\_tags](#input\_commands\_extra\_tags) | Extra tags for Elasticache redis commands monitor | `list(string)` | `[]` | no | +| [commands\_message](#input\_commands\_message) | Custom message for Elasticache redis commands monitor | `string` | `""` | no | +| [commands\_timeframe](#input\_commands\_timeframe) | Monitor timeframe for Elasticache redis commands [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [cpu\_high\_enabled](#input\_cpu\_high\_enabled) | Flag to enable Elasticache redis cpu high monitor | `string` | `"true"` | no | +| [cpu\_high\_extra\_tags](#input\_cpu\_high\_extra\_tags) | Extra tags for Elasticache redis cpu high monitor | `list(string)` | `[]` | no | +| [cpu\_high\_message](#input\_cpu\_high\_message) | Custom message for Elasticache redis cpu high monitor | `string` | `""` | no | +| [cpu\_high\_threshold\_critical](#input\_cpu\_high\_threshold\_critical) | Elasticache redis cpu high critical threshold in percentage | `string` | `90` | no | +| [cpu\_high\_threshold\_warning](#input\_cpu\_high\_threshold\_warning) | Elasticache redis cpu high warning threshold in percentage | `string` | `75` | no | +| [cpu\_high\_time\_aggregator](#input\_cpu\_high\_time\_aggregator) | Monitor aggregator for Elasticache redis cpu high [available values: min, max or avg] | `string` | `"min"` | no | +| [cpu\_high\_timeframe](#input\_cpu\_high\_timeframe) | Monitor timeframe for Elasticache redis cpu high [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [environment](#input\_environment) | Infrastructure Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [redis\_cpu\_high\_no\_data\_timeframe](#input\_redis\_cpu\_high\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `30` | no | +| [replication\_lag\_enabled](#input\_replication\_lag\_enabled) | Flag to enable Elasticache redis replication lag monitor | `string` | `"true"` | no | +| [replication\_lag\_extra\_tags](#input\_replication\_lag\_extra\_tags) | Extra tags for Elasticache redis replication lag monitor | `list(string)` | `[]` | no | +| [replication\_lag\_message](#input\_replication\_lag\_message) | Custom message for Elasticache redis replication lag monitor | `string` | `""` | no | +| [replication\_lag\_threshold\_critical](#input\_replication\_lag\_threshold\_critical) | Elasticache redis replication lag critical threshold in seconds | `string` | `180` | no | +| [replication\_lag\_threshold\_warning](#input\_replication\_lag\_threshold\_warning) | Elasticache redis replication lag warning threshold in seconds | `string` | `90` | no | +| [replication\_lag\_time\_aggregator](#input\_replication\_lag\_time\_aggregator) | Monitor aggregator for Elasticache redis replication lag [available values: min, max or avg] | `string` | `"min"` | no | +| [replication\_lag\_timeframe](#input\_replication\_lag\_timeframe) | Monitor timeframe for Elasticache redis replication lag [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_10m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [redis\_cache\_hits\_id](#output\_redis\_cache\_hits\_id) | id for monitor redis\_cache\_hits | +| [redis\_commands\_id](#output\_redis\_commands\_id) | id for monitor redis\_commands | +| [redis\_cpu\_high\_id](#output\_redis\_cpu\_high\_id) | id for monitor redis\_cpu\_high | +| [redis\_replication\_lag\_id](#output\_redis\_replication\_lag\_id) | id for monitor redis\_replication\_lag | +## Related documentation + +* [https://docs.datadoghq.com/integrations/amazon_elasticache/](https://docs.datadoghq.com/integrations/amazon_elasticache/) +* [https://www.datadoghq.com/blog/monitoring-elasticache-performance-metrics-with-redis-or-memcached/](https://www.datadoghq.com/blog/monitoring-elasticache-performance-metrics-with-redis-or-memcached/) + + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/redis/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/redis/inputs.tf new file mode 100755 index 0000000..7e391cf --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/redis/inputs.tf @@ -0,0 +1,204 @@ +# Global Terraform +variable "environment" { + description = "Infrastructure Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "redis_cpu_high_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 30 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# redis specific + +variable "cache_hits_enabled" { + description = "Flag to enable Elasticache redis cache hits monitor" + type = string + default = "true" +} + +variable "cache_hits_extra_tags" { + description = "Extra tags for Elasticache redis cache hits monitor" + type = list(string) + default = [] +} + +variable "cache_hits_message" { + description = "Custom message for Elasticache redis cache hits monitor" + type = string + default = "" +} + +variable "cache_hits_time_aggregator" { + description = "Monitor aggregator for Elasticache redis cache hits [available values: min, max or avg]" + type = string + default = "max" +} + +variable "cache_hits_timeframe" { + description = "Monitor timeframe for Elasticache redis cache hits [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "cache_hits_threshold_warning" { + description = "Elasticache redis cache hits warning threshold in percentage" + type = string + default = 80 +} + +variable "cache_hits_threshold_critical" { + description = "Elasticache redis cache hits critical threshold in percentage" + type = string + default = 60 +} + +variable "cpu_high_enabled" { + description = "Flag to enable Elasticache redis cpu high monitor" + type = string + default = "true" +} + +variable "cpu_high_extra_tags" { + description = "Extra tags for Elasticache redis cpu high monitor" + type = list(string) + default = [] +} + +variable "cpu_high_message" { + description = "Custom message for Elasticache redis cpu high monitor" + type = string + default = "" +} + +variable "cpu_high_time_aggregator" { + description = "Monitor aggregator for Elasticache redis cpu high [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cpu_high_timeframe" { + description = "Monitor timeframe for Elasticache redis cpu high [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "cpu_high_threshold_warning" { + description = "Elasticache redis cpu high warning threshold in percentage" + type = string + default = 75 +} + +variable "cpu_high_threshold_critical" { + description = "Elasticache redis cpu high critical threshold in percentage" + type = string + default = 90 +} + +variable "replication_lag_enabled" { + description = "Flag to enable Elasticache redis replication lag monitor" + type = string + default = "true" +} + +variable "replication_lag_extra_tags" { + description = "Extra tags for Elasticache redis replication lag monitor" + type = list(string) + default = [] +} + +variable "replication_lag_message" { + description = "Custom message for Elasticache redis replication lag monitor" + type = string + default = "" +} + +variable "replication_lag_time_aggregator" { + description = "Monitor aggregator for Elasticache redis replication lag [available values: min, max or avg]" + type = string + default = "min" +} + +variable "replication_lag_timeframe" { + description = "Monitor timeframe for Elasticache redis replication lag [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_10m" +} + +variable "replication_lag_threshold_warning" { + description = "Elasticache redis replication lag warning threshold in seconds" + type = string + default = 90 +} + +variable "replication_lag_threshold_critical" { + description = "Elasticache redis replication lag critical threshold in seconds" + type = string + default = 180 +} + +variable "commands_enabled" { + description = "Flag to enable Elasticache redis commands monitor" + type = string + default = "true" +} + +variable "commands_extra_tags" { + description = "Extra tags for Elasticache redis commands monitor" + type = list(string) + default = [] +} + +variable "commands_message" { + description = "Custom message for Elasticache redis commands monitor" + type = string + default = "" +} + +variable "commands_timeframe" { + description = "Monitor timeframe for Elasticache redis commands [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/redis/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/redis/modules.tf new file mode 100755 index 0000000..1b317be --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/redis/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../../common/filter-tags" + + environment = var.environment + resource = "aws_elasticache" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/redis/monitors-redis.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/redis/monitors-redis.tf new file mode 100755 index 0000000..1a9466b --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticache/redis/monitors-redis.tf @@ -0,0 +1,114 @@ +resource "datadog_monitor" "redis_cache_hits" { + count = var.cache_hits_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticache redis cache hit ratio {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cache_hits_message, var.message) + type = "query alert" + + query = < ${var.cpu_high_threshold_critical} +EOQ + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = var.notify_no_data + no_data_timeframe = var.redis_cpu_high_no_data_timeframe + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elasticache-redis", "team:claranet", "created-by:terraform", "engine:redis"], var.cpu_high_extra_tags) +} + +resource "datadog_monitor" "redis_replication_lag" { + count = var.replication_lag_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticache redis replication lag {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + message = coalesce(var.replication_lag_message, var.message) + type = "query alert" + + query = < ${var.replication_lag_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.replication_lag_threshold_warning + critical = var.replication_lag_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elasticache-redis", "team:claranet", "created-by:terraform", "engine:redis"], var.replication_lag_extra_tags) +} + +resource "datadog_monitor" "redis_commands" { + count = var.commands_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticache redis is receiving no commands" + message = coalesce(var.commands_message, var.message) + type = "query alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.es_cluster_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.es_cpu_90_15min](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.es_free_space_low](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_enabled](#input\_cpu\_enabled) | Flag to enable ES cluster cpu monitor | `string` | `"true"` | no | +| [cpu\_extra\_tags](#input\_cpu\_extra\_tags) | Extra tags for ES cluster cpu monitor | `list(string)` | `[]` | no | +| [cpu\_message](#input\_cpu\_message) | Custom message for ES cluster cpu monitor | `string` | `""` | no | +| [cpu\_threshold\_critical](#input\_cpu\_threshold\_critical) | CPU usage in percent (critical threshold) | `string` | `"90"` | no | +| [cpu\_threshold\_warning](#input\_cpu\_threshold\_warning) | CPU usage in percent (warning threshold) | `string` | `"80"` | no | +| [cpu\_time\_aggregator](#input\_cpu\_time\_aggregator) | Monitor aggregator for ES cluster cpu [available values: min, max or avg] | `string` | `"min"` | no | +| [cpu\_timeframe](#input\_cpu\_timeframe) | Monitor timeframe for ES cluster cpu [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [diskspace\_enabled](#input\_diskspace\_enabled) | Flag to enable ES cluster diskspace monitor | `string` | `"true"` | no | +| [diskspace\_extra\_tags](#input\_diskspace\_extra\_tags) | Extra tags for ES cluster diskspace monitor | `list(string)` | `[]` | no | +| [diskspace\_message](#input\_diskspace\_message) | Custom message for ES cluster diskspace monitor | `string` | `""` | no | +| [diskspace\_threshold\_critical](#input\_diskspace\_threshold\_critical) | Disk free space in percent (critical threshold) | `string` | `"10"` | no | +| [diskspace\_threshold\_warning](#input\_diskspace\_threshold\_warning) | Disk free space in percent (warning threshold) | `string` | `"20"` | no | +| [diskspace\_time\_aggregator](#input\_diskspace\_time\_aggregator) | Monitor aggregator for ES cluster diskspace [available values: min, max or avg] | `string` | `"max"` | no | +| [diskspace\_timeframe](#input\_diskspace\_timeframe) | Monitor timeframe for ES cluster diskspace [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [es\_cluster\_status\_enabled](#input\_es\_cluster\_status\_enabled) | Flag to enable ES cluster status monitor | `string` | `"true"` | no | +| [es\_cluster\_status\_extra\_tags](#input\_es\_cluster\_status\_extra\_tags) | Extra tags for ES cluster status monitor | `list(string)` | `[]` | no | +| [es\_cluster\_status\_message](#input\_es\_cluster\_status\_message) | Custom message for ES cluster status monitor | `string` | `""` | no | +| [es\_cluster\_status\_no\_data\_timeframe](#input\_es\_cluster\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `60` | no | +| [es\_cluster\_status\_timeframe](#input\_es\_cluster\_status\_timeframe) | Monitor timeframe for ES cluster status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_30m"` | no | +| [es\_cluster\_volume\_size](#input\_es\_cluster\_volume\_size) | ElasticSearch Domain volume size (in GB) | `any` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [es\_cluster\_status\_id](#output\_es\_cluster\_status\_id) | id for monitor es\_cluster\_status | +| [es\_cpu\_90\_15min\_id](#output\_es\_cpu\_90\_15min\_id) | id for monitor es\_cpu\_90\_15min | +| [es\_free\_space\_low\_id](#output\_es\_free\_space\_low\_id) | id for monitor es\_free\_space\_low | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/amazon_es/](https://docs.datadoghq.com/integrations/amazon_es/) + +AWS ElasticSearch Service Instance metrics documentation: [https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/es-metricscollected.html](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/es-metricscollected.html) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticsearch/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticsearch/inputs.tf new file mode 100755 index 0000000..8fa1648 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticsearch/inputs.tf @@ -0,0 +1,162 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "es_cluster_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 60 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# AWS ElasticSearch Service specific + +variable "es_cluster_status_enabled" { + description = "Flag to enable ES cluster status monitor" + type = string + default = "true" +} + +variable "es_cluster_status_extra_tags" { + description = "Extra tags for ES cluster status monitor" + type = list(string) + default = [] +} + +variable "es_cluster_status_message" { + description = "Custom message for ES cluster status monitor" + type = string + default = "" +} + +variable "es_cluster_status_timeframe" { + description = "Monitor timeframe for ES cluster status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_30m" +} + +variable "es_cluster_volume_size" { + description = "ElasticSearch Domain volume size (in GB)" +} + +variable "diskspace_enabled" { + description = "Flag to enable ES cluster diskspace monitor" + type = string + default = "true" +} + +variable "diskspace_extra_tags" { + description = "Extra tags for ES cluster diskspace monitor" + type = list(string) + default = [] +} + +variable "diskspace_message" { + description = "Custom message for ES cluster diskspace monitor" + type = string + default = "" +} + +variable "diskspace_time_aggregator" { + description = "Monitor aggregator for ES cluster diskspace [available values: min, max or avg]" + type = string + default = "max" +} + +variable "diskspace_timeframe" { + description = "Monitor timeframe for ES cluster diskspace [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "diskspace_threshold_warning" { + description = "Disk free space in percent (warning threshold)" + default = "20" +} + +variable "diskspace_threshold_critical" { + description = "Disk free space in percent (critical threshold)" + default = "10" +} + +variable "cpu_enabled" { + description = "Flag to enable ES cluster cpu monitor" + type = string + default = "true" +} + +variable "cpu_extra_tags" { + description = "Extra tags for ES cluster cpu monitor" + type = list(string) + default = [] +} + +variable "cpu_message" { + description = "Custom message for ES cluster cpu monitor" + type = string + default = "" +} + +variable "cpu_time_aggregator" { + description = "Monitor aggregator for ES cluster cpu [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cpu_timeframe" { + description = "Monitor timeframe for ES cluster cpu [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "cpu_threshold_warning" { + description = "CPU usage in percent (warning threshold)" + default = "80" +} + +variable "cpu_threshold_critical" { + description = "CPU usage in percent (critical threshold)" + default = "90" +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticsearch/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticsearch/modules.tf new file mode 100755 index 0000000..e259384 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticsearch/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "aws_elasticsearch" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticsearch/monitors-elasticsearch.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticsearch/monitors-elasticsearch.tf new file mode 100755 index 0000000..bd73e31 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticsearch/monitors-elasticsearch.tf @@ -0,0 +1,100 @@ +### Elasticsearch cluster status monitor ### +/* Note about the query + - If aws.es.cluster_statusred is 1 --> query value (= 2.1) > 2 : critical + - If aws.es.cluster_statusyellow is 1 --> 1 < query value (=1.1) < 2 : warning + Workaround : in the query, we add "0.1" to the result and we use the comparator ">=". No alert was triggered without that. */ +resource "datadog_monitor" "es_cluster_status" { + count = var.es_cluster_status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ElasticSearch cluster status is not green" + message = coalesce(var.es_cluster_status_message, var.message) + type = "query alert" + + query = <= 2 +EOQ + + monitor_thresholds { + warning = 1 + critical = 2 + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = var.notify_no_data + no_data_timeframe = var.es_cluster_status_no_data_timeframe + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.es_cluster_status_extra_tags) +} + +### Elasticsearch cluster free storage space monitor ### +resource "datadog_monitor" "es_free_space_low" { + count = var.diskspace_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ElasticSearch cluster free storage space {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.diskspace_message, var.message) + type = "query alert" + + query = < ${var.cpu_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.cpu_threshold_warning + critical = var.cpu_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.cpu_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticsearch/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticsearch/outputs.tf new file mode 100755 index 0000000..b55a5a2 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticsearch/outputs.tf @@ -0,0 +1,15 @@ +output "es_cluster_status_id" { + description = "id for monitor es_cluster_status" + value = datadog_monitor.es_cluster_status.*.id +} + +output "es_cpu_90_15min_id" { + description = "id for monitor es_cpu_90_15min" + value = datadog_monitor.es_cpu_90_15min.*.id +} + +output "es_free_space_low_id" { + description = "id for monitor es_free_space_low" + value = datadog_monitor.es_free_space_low.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticsearch/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticsearch/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elasticsearch/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elb/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elb/README.md new file mode 100755 index 0000000..174cf84 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elb/README.md @@ -0,0 +1,124 @@ +# CLOUD AWS ELB DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-elb" { + source = "claranet/monitors/datadog//cloud/aws/elb" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- ELB 4xx errors too high +- ELB 5xx errors too high +- ELB backend 4xx errors too high +- ELB backend 5xx errors too high +- ELB healthy instances +- ELB latency too high + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.ELB_backend_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ELB_no_healthy_instances](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ELB_too_much_4xx](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ELB_too_much_4xx_backend](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ELB_too_much_5xx](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.ELB_too_much_5xx_backend](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [artificial\_requests\_count](#input\_artificial\_requests\_count) | Number of false requests used to mitigate false positive in case of low trafic | `number` | `5` | no | +| [elb\_4xx\_enabled](#input\_elb\_4xx\_enabled) | Flag to enable ELB 4xx errors monitor | `string` | `"true"` | no | +| [elb\_4xx\_extra\_tags](#input\_elb\_4xx\_extra\_tags) | Extra tags for ELB 4xx errors monitor | `list(string)` | `[]` | no | +| [elb\_4xx\_message](#input\_elb\_4xx\_message) | Custom message for ELB 4xx errors monitor | `string` | `""` | no | +| [elb\_4xx\_threshold\_critical](#input\_elb\_4xx\_threshold\_critical) | loadbalancer 4xx critical threshold in percentage | `number` | `10` | no | +| [elb\_4xx\_threshold\_warning](#input\_elb\_4xx\_threshold\_warning) | loadbalancer 4xx warning threshold in percentage | `number` | `5` | no | +| [elb\_4xx\_timeframe](#input\_elb\_4xx\_timeframe) | Monitor timeframe for ELB 4xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [elb\_5xx\_enabled](#input\_elb\_5xx\_enabled) | Flag to enable ELB 5xx errors monitor | `string` | `"true"` | no | +| [elb\_5xx\_extra\_tags](#input\_elb\_5xx\_extra\_tags) | Extra tags for ELB 5xx errors monitor | `list(string)` | `[]` | no | +| [elb\_5xx\_message](#input\_elb\_5xx\_message) | Custom message for ELB 5xx errors monitor | `string` | `""` | no | +| [elb\_5xx\_threshold\_critical](#input\_elb\_5xx\_threshold\_critical) | loadbalancer 5xx critical threshold in percentage | `number` | `10` | no | +| [elb\_5xx\_threshold\_warning](#input\_elb\_5xx\_threshold\_warning) | loadbalancer 5xx warning threshold in percentage | `number` | `5` | no | +| [elb\_5xx\_timeframe](#input\_elb\_5xx\_timeframe) | Monitor timeframe for ELB 5xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [elb\_backend\_4xx\_enabled](#input\_elb\_backend\_4xx\_enabled) | Flag to enable ELB backend 4xx errors monitor | `string` | `"true"` | no | +| [elb\_backend\_4xx\_extra\_tags](#input\_elb\_backend\_4xx\_extra\_tags) | Extra tags for ELB backend 4xx errors monitor | `list(string)` | `[]` | no | +| [elb\_backend\_4xx\_message](#input\_elb\_backend\_4xx\_message) | Custom message for ELB backend 4xx errors monitor | `string` | `""` | no | +| [elb\_backend\_4xx\_threshold\_critical](#input\_elb\_backend\_4xx\_threshold\_critical) | loadbalancer backend 4xx critical threshold in percentage | `number` | `10` | no | +| [elb\_backend\_4xx\_threshold\_warning](#input\_elb\_backend\_4xx\_threshold\_warning) | loadbalancer backend 4xx warning threshold in percentage | `number` | `5` | no | +| [elb\_backend\_4xx\_timeframe](#input\_elb\_backend\_4xx\_timeframe) | Monitor timeframe for ELB backend 4xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [elb\_backend\_5xx\_enabled](#input\_elb\_backend\_5xx\_enabled) | Flag to enable ELB backend 5xx errors monitor | `string` | `"true"` | no | +| [elb\_backend\_5xx\_extra\_tags](#input\_elb\_backend\_5xx\_extra\_tags) | Extra tags for ELB backend 5xx errors monitor | `list(string)` | `[]` | no | +| [elb\_backend\_5xx\_message](#input\_elb\_backend\_5xx\_message) | Custom message for ELB backend 5xx errors monitor | `string` | `""` | no | +| [elb\_backend\_5xx\_threshold\_critical](#input\_elb\_backend\_5xx\_threshold\_critical) | loadbalancer backend 5xx critical threshold in percentage | `number` | `10` | no | +| [elb\_backend\_5xx\_threshold\_warning](#input\_elb\_backend\_5xx\_threshold\_warning) | loadbalancer backend 5xx warning threshold in percentage | `number` | `5` | no | +| [elb\_backend\_5xx\_timeframe](#input\_elb\_backend\_5xx\_timeframe) | Monitor timeframe for ELB backend 5xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [elb\_backend\_latency\_critical](#input\_elb\_backend\_latency\_critical) | latency critical threshold in seconds | `number` | `3` | no | +| [elb\_backend\_latency\_enabled](#input\_elb\_backend\_latency\_enabled) | Flag to enable ELB backend latency monitor | `string` | `"true"` | no | +| [elb\_backend\_latency\_extra\_tags](#input\_elb\_backend\_latency\_extra\_tags) | Extra tags for ELB backend latency monitor | `list(string)` | `[]` | no | +| [elb\_backend\_latency\_message](#input\_elb\_backend\_latency\_message) | Custom message for ELB backend latency monitor | `string` | `""` | no | +| [elb\_backend\_latency\_time\_aggregator](#input\_elb\_backend\_latency\_time\_aggregator) | Monitor aggregator for ELB backend latency [available values: min, max or avg] | `string` | `"min"` | no | +| [elb\_backend\_latency\_timeframe](#input\_elb\_backend\_latency\_timeframe) | Monitor timeframe for ELB backend latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [elb\_backend\_latency\_warning](#input\_elb\_backend\_latency\_warning) | latency warning threshold in seconds | `number` | `1` | no | +| [elb\_no\_healthy\_instance\_enabled](#input\_elb\_no\_healthy\_instance\_enabled) | Flag to enable ELB no healty instance monitor | `string` | `"true"` | no | +| [elb\_no\_healthy\_instance\_extra\_tags](#input\_elb\_no\_healthy\_instance\_extra\_tags) | Extra tags for ELB no healty instance monitor | `list(string)` | `[]` | no | +| [elb\_no\_healthy\_instance\_message](#input\_elb\_no\_healthy\_instance\_message) | Custom message for ELB no healty instance monitor | `string` | `""` | no | +| [elb\_no\_healthy\_instance\_no\_data\_timeframe](#input\_elb\_no\_healthy\_instance\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [elb\_no\_healthy\_instance\_threshold\_warning](#input\_elb\_no\_healthy\_instance\_threshold\_warning) | ELB no healthy instances warning threshold in percentage | `number` | `100` | no | +| [elb\_no\_healthy\_instance\_time\_aggregator](#input\_elb\_no\_healthy\_instance\_time\_aggregator) | Monitor aggregator for ELB no healty instance [available values: min or max] | `string` | `"min"` | no | +| [elb\_no\_healthy\_instance\_timeframe](#input\_elb\_no\_healthy\_instance\_timeframe) | Monitor timeframe for ELB no healty instance [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [ELB\_backend\_latency\_id](#output\_ELB\_backend\_latency\_id) | id for monitor ELB\_backend\_latency | +| [ELB\_no\_healthy\_instances\_id](#output\_ELB\_no\_healthy\_instances\_id) | id for monitor ELB\_no\_healthy\_instances | +| [ELB\_too\_much\_4xx\_backend\_id](#output\_ELB\_too\_much\_4xx\_backend\_id) | id for monitor ELB\_too\_much\_4xx\_backend | +| [ELB\_too\_much\_4xx\_id](#output\_ELB\_too\_much\_4xx\_id) | id for monitor ELB\_too\_much\_4xx | +| [ELB\_too\_much\_5xx\_backend\_id](#output\_ELB\_too\_much\_5xx\_backend\_id) | id for monitor ELB\_too\_much\_5xx\_backend | +| [ELB\_too\_much\_5xx\_id](#output\_ELB\_too\_much\_5xx\_id) | id for monitor ELB\_too\_much\_5xx | +## Related documentation + +DataDog blog: [https://www.datadoghq.com/blog/monitor-application-load-balancer/](https://www.datadoghq.com/blog/monitor-application-load-balancer/) + +AWS ELB metrics documentation: [https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-cloudwatch-metrics.html](https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-cloudwatch-metrics.html) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elb/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elb/inputs.tf new file mode 100755 index 0000000..ce8c827 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elb/inputs.tf @@ -0,0 +1,270 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "elb_no_healthy_instance_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +## ELB + +variable "elb_no_healthy_instance_enabled" { + description = "Flag to enable ELB no healty instance monitor" + type = string + default = "true" +} + +variable "elb_no_healthy_instance_extra_tags" { + description = "Extra tags for ELB no healty instance monitor" + type = list(string) + default = [] +} + +variable "elb_no_healthy_instance_message" { + description = "Custom message for ELB no healty instance monitor" + type = string + default = "" +} + +variable "elb_no_healthy_instance_time_aggregator" { + description = "Monitor aggregator for ELB no healty instance [available values: min or max]" + type = string + default = "min" +} + +variable "elb_no_healthy_instance_timeframe" { + description = "Monitor timeframe for ELB no healty instance [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "elb_no_healthy_instance_threshold_warning" { + description = "ELB no healthy instances warning threshold in percentage" + default = 100 +} + +variable "elb_4xx_enabled" { + description = "Flag to enable ELB 4xx errors monitor" + type = string + default = "true" +} + +variable "elb_4xx_extra_tags" { + description = "Extra tags for ELB 4xx errors monitor" + type = list(string) + default = [] +} + +variable "elb_4xx_message" { + description = "Custom message for ELB 4xx errors monitor" + type = string + default = "" +} + +variable "elb_4xx_timeframe" { + description = "Monitor timeframe for ELB 4xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "elb_4xx_threshold_warning" { + description = "loadbalancer 4xx warning threshold in percentage" + default = 5 +} + +variable "elb_4xx_threshold_critical" { + description = "loadbalancer 4xx critical threshold in percentage" + default = 10 +} + +variable "elb_5xx_enabled" { + description = "Flag to enable ELB 5xx errors monitor" + type = string + default = "true" +} + +variable "elb_5xx_extra_tags" { + description = "Extra tags for ELB 5xx errors monitor" + type = list(string) + default = [] +} + +variable "elb_5xx_message" { + description = "Custom message for ELB 5xx errors monitor" + type = string + default = "" +} + +variable "elb_5xx_timeframe" { + description = "Monitor timeframe for ELB 5xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "elb_5xx_threshold_warning" { + description = "loadbalancer 5xx warning threshold in percentage" + default = 5 +} + +variable "elb_5xx_threshold_critical" { + description = "loadbalancer 5xx critical threshold in percentage" + default = 10 +} + +variable "elb_backend_4xx_enabled" { + description = "Flag to enable ELB backend 4xx errors monitor" + type = string + default = "true" +} + +variable "elb_backend_4xx_extra_tags" { + description = "Extra tags for ELB backend 4xx errors monitor" + type = list(string) + default = [] +} + +variable "elb_backend_4xx_message" { + description = "Custom message for ELB backend 4xx errors monitor" + type = string + default = "" +} + +variable "elb_backend_4xx_timeframe" { + description = "Monitor timeframe for ELB backend 4xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "elb_backend_4xx_threshold_warning" { + description = "loadbalancer backend 4xx warning threshold in percentage" + default = 5 +} + +variable "elb_backend_4xx_threshold_critical" { + description = "loadbalancer backend 4xx critical threshold in percentage" + default = 10 +} + +variable "elb_backend_5xx_enabled" { + description = "Flag to enable ELB backend 5xx errors monitor" + type = string + default = "true" +} + +variable "elb_backend_5xx_extra_tags" { + description = "Extra tags for ELB backend 5xx errors monitor" + type = list(string) + default = [] +} + +variable "elb_backend_5xx_message" { + description = "Custom message for ELB backend 5xx errors monitor" + type = string + default = "" +} + +variable "elb_backend_5xx_timeframe" { + description = "Monitor timeframe for ELB backend 5xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "elb_backend_5xx_threshold_warning" { + description = "loadbalancer backend 5xx warning threshold in percentage" + default = 5 +} + +variable "elb_backend_5xx_threshold_critical" { + description = "loadbalancer backend 5xx critical threshold in percentage" + default = 10 +} + +variable "elb_backend_latency_enabled" { + description = "Flag to enable ELB backend latency monitor" + type = string + default = "true" +} + +variable "elb_backend_latency_extra_tags" { + description = "Extra tags for ELB backend latency monitor" + type = list(string) + default = [] +} + +variable "elb_backend_latency_message" { + description = "Custom message for ELB backend latency monitor" + type = string + default = "" +} + +variable "elb_backend_latency_time_aggregator" { + description = "Monitor aggregator for ELB backend latency [available values: min, max or avg]" + type = string + default = "min" +} + +variable "elb_backend_latency_timeframe" { + description = "Monitor timeframe for ELB backend latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "elb_backend_latency_warning" { + description = "latency warning threshold in seconds" + default = 1 +} + +variable "elb_backend_latency_critical" { + description = "latency critical threshold in seconds" + default = 3 +} + +variable "artificial_requests_count" { + default = 5 + description = "Number of false requests used to mitigate false positive in case of low trafic" +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elb/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elb/modules.tf new file mode 100755 index 0000000..9d396f6 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elb/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "aws_elb" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elb/monitors-elb.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elb/monitors-elb.tf new file mode 100755 index 0000000..c936852 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elb/monitors-elb.tf @@ -0,0 +1,187 @@ +resource "datadog_monitor" "ELB_no_healthy_instances" { + count = var.elb_no_healthy_instance_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ELB healthy instances {{#is_alert}}is at 0{{/is_alert}}{{#is_warning}}is at {{value}}%%{{/is_warning}}" + message = coalesce(var.elb_no_healthy_instance_message, var.message) + type = "query alert" + + query = < ${var.elb_4xx_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.elb_4xx_threshold_warning + critical = var.elb_4xx_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elb", "team:claranet", "created-by:terraform"], var.elb_4xx_extra_tags) +} + +resource "datadog_monitor" "ELB_too_much_5xx" { + count = var.elb_5xx_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ELB 5xx errors too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.elb_5xx_message, var.message) + type = "query alert" + + query = < ${var.elb_5xx_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.elb_5xx_threshold_warning + critical = var.elb_5xx_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elb", "team:claranet", "created-by:terraform"], var.elb_5xx_extra_tags) +} + +resource "datadog_monitor" "ELB_too_much_4xx_backend" { + count = var.elb_backend_4xx_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ELB backend 4xx errors too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.elb_backend_4xx_message, var.message) + type = "query alert" + + query = < ${var.elb_backend_4xx_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.elb_backend_4xx_threshold_warning + critical = var.elb_backend_4xx_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elb", "team:claranet", "created-by:terraform"], var.elb_backend_4xx_extra_tags) +} + +resource "datadog_monitor" "ELB_too_much_5xx_backend" { + count = var.elb_backend_5xx_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ELB backend 5xx errors too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.elb_backend_5xx_message, var.message) + type = "query alert" + + query = < ${var.elb_backend_5xx_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.elb_backend_5xx_threshold_warning + critical = var.elb_backend_5xx_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elb", "team:claranet", "created-by:terraform"], var.elb_backend_5xx_extra_tags) +} + +resource "datadog_monitor" "ELB_backend_latency" { + count = var.elb_backend_latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ELB latency too high {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + message = coalesce(var.elb_backend_latency_message, var.message) + type = "query alert" + + query = < ${var.elb_backend_latency_critical} +EOQ + + monitor_thresholds { + warning = var.elb_backend_latency_warning + critical = var.elb_backend_latency_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:elb", "team:claranet", "created-by:terraform"], var.elb_backend_latency_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elb/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elb/outputs.tf new file mode 100755 index 0000000..19c1dd3 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elb/outputs.tf @@ -0,0 +1,30 @@ +output "ELB_backend_latency_id" { + description = "id for monitor ELB_backend_latency" + value = datadog_monitor.ELB_backend_latency.*.id +} + +output "ELB_no_healthy_instances_id" { + description = "id for monitor ELB_no_healthy_instances" + value = datadog_monitor.ELB_no_healthy_instances.*.id +} + +output "ELB_too_much_4xx_id" { + description = "id for monitor ELB_too_much_4xx" + value = datadog_monitor.ELB_too_much_4xx.*.id +} + +output "ELB_too_much_4xx_backend_id" { + description = "id for monitor ELB_too_much_4xx_backend" + value = datadog_monitor.ELB_too_much_4xx_backend.*.id +} + +output "ELB_too_much_5xx_id" { + description = "id for monitor ELB_too_much_5xx" + value = datadog_monitor.ELB_too_much_5xx.*.id +} + +output "ELB_too_much_5xx_backend_id" { + description = "id for monitor ELB_too_much_5xx_backend" + value = datadog_monitor.ELB_too_much_5xx_backend.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elb/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elb/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/elb/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/kinesis-firehose/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/kinesis-firehose/README.md new file mode 100755 index 0000000..ef2d55c --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/kinesis-firehose/README.md @@ -0,0 +1,75 @@ +# CLOUD AWS KINESIS-FIREHOSE DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-kinesis-firehose" { + source = "claranet/monitors/datadog//cloud/aws/kinesis-firehose" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Kinesis Firehose No incoming records + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.firehose_incoming_records](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [firehose\_incoming\_records\_no\_data\_timeframe](#input\_firehose\_incoming\_records\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `30` | no | +| [incoming\_records\_enabled](#input\_incoming\_records\_enabled) | Flag to enable Kinesis Firehorse incoming records monitor | `string` | `"true"` | no | +| [incoming\_records\_extra\_tags](#input\_incoming\_records\_extra\_tags) | Extra tags for Kinesis Firehorse incoming records monitor | `list(string)` | `[]` | no | +| [incoming\_records\_message](#input\_incoming\_records\_message) | Custom message for Kinesis Firehorse incoming records monitor | `string` | `""` | no | +| [incoming\_records\_timeframe](#input\_incoming\_records\_timeframe) | Monitor timeframe for incoming records metrics evaluation [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [firehose\_incoming\_records\_id](#output\_firehose\_incoming\_records\_id) | id for monitor firehose\_incoming\_records | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/amazon_firehose/](https://docs.datadoghq.com/integrations/amazon_firehose/) + +AWS Kinesis Firehose metrics documentation: [https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/akf-metricscollected.html](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/akf-metricscollected.html) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/kinesis-firehose/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/kinesis-firehose/inputs.tf new file mode 100755 index 0000000..df1bc09 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/kinesis-firehose/inputs.tf @@ -0,0 +1,77 @@ +# Global Terraform +variable "environment" { + description = "Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "firehose_incoming_records_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 30 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Kinesis-Firehose + +variable "incoming_records_enabled" { + description = "Flag to enable Kinesis Firehorse incoming records monitor" + type = string + default = "true" +} + +variable "incoming_records_extra_tags" { + description = "Extra tags for Kinesis Firehorse incoming records monitor" + type = list(string) + default = [] +} + +variable "incoming_records_message" { + description = "Custom message for Kinesis Firehorse incoming records monitor" + type = string + default = "" +} + +variable "incoming_records_timeframe" { + description = "Monitor timeframe for incoming records metrics evaluation [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + default = "last_15m" +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/kinesis-firehose/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/kinesis-firehose/modules.tf new file mode 100755 index 0000000..f9113f5 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/kinesis-firehose/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "aws_kinesis-firehose" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/kinesis-firehose/monitors-kinesis-firehose.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/kinesis-firehose/monitors-kinesis-firehose.tf new file mode 100755 index 0000000..e0fb7a0 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/kinesis-firehose/monitors-kinesis-firehose.tf @@ -0,0 +1,31 @@ +### Kinesis Firehose Incoming records ### +resource "datadog_monitor" "firehose_incoming_records" { + count = var.incoming_records_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Kinesis Firehose No incoming records" + message = coalesce(var.incoming_records_message, var.message) + type = "query alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.invocations](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.pct_errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.throttles](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [errors\_enabled](#input\_errors\_enabled) | Flag to enable Errors monitor | `string` | `"false"` | no | +| [errors\_extra\_tags](#input\_errors\_extra\_tags) | Extra tags for Errors monitor | `list(string)` | `[]` | no | +| [errors\_message](#input\_errors\_message) | Custom message for Errors monitor | `string` | `""` | no | +| [errors\_threshold\_critical](#input\_errors\_threshold\_critical) | Alerting threshold in milliseconds | `number` | `3` | no | +| [errors\_threshold\_warning](#input\_errors\_threshold\_warning) | Warning threshold in milliseconds | `number` | `1` | no | +| [errors\_time\_aggregator](#input\_errors\_time\_aggregator) | Monitor aggregator for Errors [available values: min, max or avg] | `string` | `"sum"` | no | +| [errors\_timeframe](#input\_errors\_timeframe) | Monitor timeframe for Errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1h"` | no | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [invocations\_enabled](#input\_invocations\_enabled) | Flag to enable Invocations monitor | `string` | `"false"` | no | +| [invocations\_extra\_tags](#input\_invocations\_extra\_tags) | Extra tags for Invocations monitor | `list(string)` | `[]` | no | +| [invocations\_message](#input\_invocations\_message) | Custom message for Invocations monitor | `string` | `""` | no | +| [invocations\_no\_data\_timeframe](#input\_invocations\_no\_data\_timeframe) | Timeframe to check before alerting on no data in minutes | `number` | `120` | no | +| [invocations\_threshold\_critical](#input\_invocations\_threshold\_critical) | Alerting threshold in number of invocations | `number` | `1` | no | +| [invocations\_threshold\_warning](#input\_invocations\_threshold\_warning) | Warning threshold in number of invocations | `number` | `2` | no | +| [invocations\_time\_aggregator](#input\_invocations\_time\_aggregator) | Monitor aggregator for Invocations [available values: min, max or avg] | `string` | `"sum"` | no | +| [invocations\_timeframe](#input\_invocations\_timeframe) | Monitor timeframe for Invocations [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_30m"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [pct\_errors\_enabled](#input\_pct\_errors\_enabled) | Flag to enable Percentage of errors monitor | `string` | `"true"` | no | +| [pct\_errors\_extra\_tags](#input\_pct\_errors\_extra\_tags) | Extra tags for Percentage of errors monitor | `list(string)` | `[]` | no | +| [pct\_errors\_message](#input\_pct\_errors\_message) | Custom message for Percentage of errors monitor | `string` | `""` | no | +| [pct\_errors\_threshold\_critical](#input\_pct\_errors\_threshold\_critical) | Alerting threshold in percentage | `number` | `30` | no | +| [pct\_errors\_threshold\_warning](#input\_pct\_errors\_threshold\_warning) | Warning threshold in percentage | `number` | `20` | no | +| [pct\_errors\_time\_aggregator](#input\_pct\_errors\_time\_aggregator) | Monitor aggregator for Percentage of errors [available values: min, max or avg] | `string` | `"sum"` | no | +| [pct\_errors\_timeframe](#input\_pct\_errors\_timeframe) | Monitor timeframe for Percentage of errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1h"` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [throttles\_enabled](#input\_throttles\_enabled) | Flag to enable Throttles monitor | `string` | `"true"` | no | +| [throttles\_extra\_tags](#input\_throttles\_extra\_tags) | Extra tags for Throttles monitor | `list(string)` | `[]` | no | +| [throttles\_message](#input\_throttles\_message) | Custom message for Throttles monitor | `string` | `""` | no | +| [throttles\_threshold\_critical](#input\_throttles\_threshold\_critical) | Alerting threshold in number of throttles | `number` | `3` | no | +| [throttles\_threshold\_warning](#input\_throttles\_threshold\_warning) | Warning threshold in number of throttles | `number` | `1` | no | +| [throttles\_time\_aggregator](#input\_throttles\_time\_aggregator) | Monitor aggregator for Throttles [available values: min, max or avg] | `string` | `"sum"` | no | +| [throttles\_timeframe](#input\_throttles\_timeframe) | Monitor timeframe for Throttles [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1h"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [errors\_id](#output\_errors\_id) | id for monitor errors | +| [invocations\_id](#output\_invocations\_id) | id for monitor invocations | +| [pct\_errors\_id](#output\_pct\_errors\_id) | id for monitor pct\_errors | +| [throttles\_id](#output\_throttles\_id) | id for monitor throttles | +## Related documentation +* [Datadog Documentation](https://docs.datadoghq.com/integrations/amazon_lambda/) +* [Service documentation](https://docs.aws.amazon.com/lambda/index.html) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/lambda/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/lambda/inputs.tf new file mode 100755 index 0000000..a8b9a24 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/lambda/inputs.tf @@ -0,0 +1,216 @@ +# Datadog global variables + +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# Datadog monitors variables + +# Percentage of errors +variable "pct_errors_enabled" { + description = "Flag to enable Percentage of errors monitor" + type = string + default = "true" +} + +variable "pct_errors_extra_tags" { + description = "Extra tags for Percentage of errors monitor" + type = list(string) + default = [] +} + +variable "pct_errors_message" { + description = "Custom message for Percentage of errors monitor" + type = string + default = "" +} + +variable "pct_errors_time_aggregator" { + description = "Monitor aggregator for Percentage of errors [available values: min, max or avg]" + type = string + default = "sum" +} + +variable "pct_errors_timeframe" { + description = "Monitor timeframe for Percentage of errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1h" +} + +variable "pct_errors_threshold_critical" { + default = 30 + description = "Alerting threshold in percentage" +} + +variable "pct_errors_threshold_warning" { + default = 20 + description = "Warning threshold in percentage" +} + +# Errors count +variable "errors_enabled" { + description = "Flag to enable Errors monitor" + type = string + default = "false" +} + +variable "errors_extra_tags" { + description = "Extra tags for Errors monitor" + type = list(string) + default = [] +} + +variable "errors_message" { + description = "Custom message for Errors monitor" + type = string + default = "" +} + +variable "errors_time_aggregator" { + description = "Monitor aggregator for Errors [available values: min, max or avg]" + type = string + default = "sum" +} + +variable "errors_timeframe" { + description = "Monitor timeframe for Errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1h" +} + +variable "errors_threshold_critical" { + default = 3 + description = "Alerting threshold in milliseconds" +} + +variable "errors_threshold_warning" { + default = 1 + description = "Warning threshold in milliseconds" +} + +# Throttles count +variable "throttles_enabled" { + description = "Flag to enable Throttles monitor" + type = string + default = "true" +} + +variable "throttles_extra_tags" { + description = "Extra tags for Throttles monitor" + type = list(string) + default = [] +} + +variable "throttles_message" { + description = "Custom message for Throttles monitor" + type = string + default = "" +} + +variable "throttles_time_aggregator" { + description = "Monitor aggregator for Throttles [available values: min, max or avg]" + type = string + default = "sum" +} + +variable "throttles_timeframe" { + description = "Monitor timeframe for Throttles [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1h" +} + +variable "throttles_threshold_critical" { + default = 3 + description = "Alerting threshold in number of throttles" +} + +variable "throttles_threshold_warning" { + default = 1 + description = "Warning threshold in number of throttles" +} + +# Invocations +variable "invocations_enabled" { + description = "Flag to enable Invocations monitor" + type = string + default = "false" +} + +variable "invocations_extra_tags" { + description = "Extra tags for Invocations monitor" + type = list(string) + default = [] +} + +variable "invocations_message" { + description = "Custom message for Invocations monitor" + type = string + default = "" +} + +variable "invocations_time_aggregator" { + description = "Monitor aggregator for Invocations [available values: min, max or avg]" + type = string + default = "sum" +} + +variable "invocations_timeframe" { + description = "Monitor timeframe for Invocations [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_30m" +} + +variable "invocations_threshold_critical" { + default = 1 + description = "Alerting threshold in number of invocations" +} + +variable "invocations_threshold_warning" { + default = 2 + description = "Warning threshold in number of invocations" +} + +variable "invocations_no_data_timeframe" { + default = 120 + description = "Timeframe to check before alerting on no data in minutes" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/lambda/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/lambda/modules.tf new file mode 100755 index 0000000..161aebe --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/lambda/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "aws_lambda" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} \ No newline at end of file diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/lambda/monitors-lambda.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/lambda/monitors-lambda.tf new file mode 100755 index 0000000..53f0616 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/lambda/monitors-lambda.tf @@ -0,0 +1,134 @@ +# Errors Percent +resource "datadog_monitor" "pct_errors" { + count = var.pct_errors_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Lambda Percentage of errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + type = "metric alert" + message = coalesce(var.pct_errors_message, var.message) + + query = < ${var.pct_errors_threshold_critical} + EOQ + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + + monitor_thresholds { + critical = var.pct_errors_threshold_critical + warning = var.pct_errors_threshold_warning + } + + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:lambda", "team:claranet", "created-by:terraform"], var.pct_errors_extra_tags) +} + +# Errors Absolute Value +resource "datadog_monitor" "errors" { + count = var.errors_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Lambda Number of errors {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + type = "metric alert" + message = coalesce(var.errors_message, var.message) + + query = < ${var.errors_threshold_critical} + EOQ + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + + monitor_thresholds { + critical = var.errors_threshold_critical + warning = var.errors_threshold_warning + } + + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:lambda", "team:claranet", "created-by:terraform"], var.errors_extra_tags) +} + +# Throttles +resource "datadog_monitor" "throttles" { + count = var.throttles_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Lambda Invocations throttled due to concurrent limit reached {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + type = "metric alert" + message = coalesce(var.throttles_message, var.message) + + query = < ${var.throttles_threshold_critical} + EOQ + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + + monitor_thresholds { + critical = var.throttles_threshold_critical + warning = var.throttles_threshold_warning + } + + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:lambda", "team:claranet", "created-by:terraform"], var.throttles_extra_tags) +} + +# INVOCATIONS +resource "datadog_monitor" "invocations" { + count = var.invocations_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Lambda Number of invocations {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + type = "metric alert" + message = coalesce(var.invocations_message, var.message) + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.NLB_no_healthy_instances](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [nlb\_no\_healthy\_instances\_enabled](#input\_nlb\_no\_healthy\_instances\_enabled) | Flag to enable NLB no healthy instances monitor | `string` | `"true"` | no | +| [nlb\_no\_healthy\_instances\_extra\_tags](#input\_nlb\_no\_healthy\_instances\_extra\_tags) | Extra tags for NLB no healthy instances monitor | `list(string)` | `[]` | no | +| [nlb\_no\_healthy\_instances\_message](#input\_nlb\_no\_healthy\_instances\_message) | Custom message for NLB no healthy instances monitor | `string` | `""` | no | +| [nlb\_no\_healthy\_instances\_no\_data\_timeframe](#input\_nlb\_no\_healthy\_instances\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [nlb\_no\_healthy\_instances\_threshold\_warning](#input\_nlb\_no\_healthy\_instances\_threshold\_warning) | NLB no healthy instances warning threshold in percentage | `number` | `100` | no | +| [nlb\_no\_healthy\_instances\_time\_aggregator](#input\_nlb\_no\_healthy\_instances\_time\_aggregator) | Monitor aggregator for NLB no healthy instances [available values: min, max or avg] | `string` | `"min"` | no | +| [nlb\_no\_healthy\_instances\_timeframe](#input\_nlb\_no\_healthy\_instances\_timeframe) | Monitor timeframe for NLB no healthy instances [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [NLB\_no\_healthy\_instances\_id](#output\_NLB\_no\_healthy\_instances\_id) | id for monitor NLB\_no\_healthy\_instances | +## Related documentation + +DataDog blog: [https://www.datadoghq.com/blog/monitor-aws-network-load-balancer/](https://www.datadoghq.com/blog/monitor-aws-network-load-balancer/) + +AWS NLB metrics documentation: [https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-cloudwatch-metrics.html](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-cloudwatch-metrics.html) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/nlb/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/nlb/inputs.tf new file mode 100755 index 0000000..3c93503 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/nlb/inputs.tf @@ -0,0 +1,88 @@ +# Datadog global variables + +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "nlb_no_healthy_instances_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# Datadog monitors variables + +variable "nlb_no_healthy_instances_enabled" { + description = "Flag to enable NLB no healthy instances monitor" + type = string + default = "true" +} + +variable "nlb_no_healthy_instances_extra_tags" { + description = "Extra tags for NLB no healthy instances monitor" + type = list(string) + default = [] +} + +variable "nlb_no_healthy_instances_message" { + description = "Custom message for NLB no healthy instances monitor" + type = string + default = "" +} + +variable "nlb_no_healthy_instances_time_aggregator" { + description = "Monitor aggregator for NLB no healthy instances [available values: min, max or avg]" + type = string + default = "min" +} + +variable "nlb_no_healthy_instances_timeframe" { + description = "Monitor timeframe for NLB no healthy instances [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "nlb_no_healthy_instances_threshold_warning" { + description = "NLB no healthy instances warning threshold in percentage" + default = 100 +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/nlb/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/nlb/modules.tf new file mode 100755 index 0000000..4899a5d --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/nlb/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "aws_nlb" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/nlb/monitors-nlb.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/nlb/monitors-nlb.tf new file mode 100755 index 0000000..2de3037 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/nlb/monitors-nlb.tf @@ -0,0 +1,31 @@ +resource "datadog_monitor" "NLB_no_healthy_instances" { + count = var.nlb_no_healthy_instances_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] NLB healthy instances {{#is_alert}}is at 0{{/is_alert}}{{#is_warning}}is at {{value}}%%{{/is_warning}}" + message = coalesce(var.nlb_no_healthy_instances_message, var.message) + type = "query alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.rds_aurora_mysql_replica_lag](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [aurora\_replicalag\_enabled](#input\_aurora\_replicalag\_enabled) | Flag to enable RDS Aurora replica lag monitor | `string` | `"true"` | no | +| [aurora\_replicalag\_extra\_tags](#input\_aurora\_replicalag\_extra\_tags) | Extra tags for RDS Aurora replica lag monitor | `list(string)` | `[]` | no | +| [aurora\_replicalag\_message](#input\_aurora\_replicalag\_message) | Custom message for RDS Aurora replica lag monitor | `string` | `""` | no | +| [aurora\_replicalag\_threshold\_critical](#input\_aurora\_replicalag\_threshold\_critical) | Aurora replica lag in milliseconds (critical threshold) | `string` | `"200"` | no | +| [aurora\_replicalag\_threshold\_warning](#input\_aurora\_replicalag\_threshold\_warning) | Aurora replica lag in milliseconds (warning threshold) | `string` | `"100"` | no | +| [aurora\_replicalag\_time\_aggregator](#input\_aurora\_replicalag\_time\_aggregator) | Monitor aggregator for RDS Aurora replica lag [available values: min, max or avg] | `string` | `"min"` | no | +| [aurora\_replicalag\_timeframe](#input\_aurora\_replicalag\_timeframe) | Monitor timeframe for RDS Aurora replica lag monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [rds\_aurora\_mysql\_replica\_lag\_no\_data\_timeframe](#input\_rds\_aurora\_mysql\_replica\_lag\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [rds\_aurora\_mysql\_replica\_lag\_id](#output\_rds\_aurora\_mysql\_replica\_lag\_id) | id for monitor rds\_aurora\_mysql\_replica\_lag | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/amazon_rds/](https://docs.datadoghq.com/integrations/amazon_rds/) + +AWS RDS Instance metrics documentation: [https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/MonitoringOverview.html#monitoring-cloudwatch](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/MonitoringOverview.html#monitoring-cloudwatch) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/mysql/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/mysql/inputs.tf new file mode 100755 index 0000000..3425832 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/mysql/inputs.tf @@ -0,0 +1,93 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "rds_aurora_mysql_replica_lag_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# AWS RDS Aurora instance specific + +variable "aurora_replicalag_enabled" { + description = "Flag to enable RDS Aurora replica lag monitor" + type = string + default = "true" +} + +variable "aurora_replicalag_extra_tags" { + description = "Extra tags for RDS Aurora replica lag monitor" + type = list(string) + default = [] +} + +variable "aurora_replicalag_message" { + description = "Custom message for RDS Aurora replica lag monitor" + type = string + default = "" +} + +variable "aurora_replicalag_time_aggregator" { + description = "Monitor aggregator for RDS Aurora replica lag [available values: min, max or avg]" + type = string + default = "min" +} + +variable "aurora_replicalag_timeframe" { + description = "Monitor timeframe for RDS Aurora replica lag monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "aurora_replicalag_threshold_warning" { + description = "Aurora replica lag in milliseconds (warning threshold)" + default = "100" +} + +variable "aurora_replicalag_threshold_critical" { + description = "Aurora replica lag in milliseconds (critical threshold)" + default = "200" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/mysql/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/mysql/modules.tf new file mode 100755 index 0000000..a5459e6 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/mysql/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../../../common/filter-tags" + + environment = var.environment + resource = "aws_rds" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/mysql/monitors-rds-aurora-mysql.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/mysql/monitors-rds-aurora-mysql.tf new file mode 100755 index 0000000..9542979 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/mysql/monitors-rds-aurora-mysql.tf @@ -0,0 +1,30 @@ +### RDS Aurora Mysql Replica Lag monitor ### +resource "datadog_monitor" "rds_aurora_mysql_replica_lag" { + count = var.aurora_replicalag_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] RDS Aurora Mysql replica lag {{#is_alert}}{{{comparator}}} {{threshold}} ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.aurora_replicalag_message, var.message) + type = "query alert" + + query = < ${var.aurora_replicalag_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.aurora_replicalag_threshold_warning + critical = var.aurora_replicalag_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = var.notify_no_data + no_data_timeframe = var.rds_aurora_mysql_replica_lag_no_data_timeframe + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:rds-aurora-mysql", "team:claranet", "created-by:terraform"], var.aurora_replicalag_extra_tags) +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/mysql/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/mysql/outputs.tf new file mode 100755 index 0000000..f94f46d --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/mysql/outputs.tf @@ -0,0 +1,5 @@ +output "rds_aurora_mysql_replica_lag_id" { + description = "id for monitor rds_aurora_mysql_replica_lag" + value = datadog_monitor.rds_aurora_mysql_replica_lag.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/mysql/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/mysql/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/mysql/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/postgresql/MANIFEST.txt b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/postgresql/MANIFEST.txt new file mode 100755 index 0000000..3d83252 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/postgresql/MANIFEST.txt @@ -0,0 +1 @@ +cloud-aws diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/postgresql/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/postgresql/README.md new file mode 100755 index 0000000..7397fae --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/postgresql/README.md @@ -0,0 +1,78 @@ +# CLOUD AWS RDS AURORA POSTGRESQL DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-rds-aurora-postgresql" { + source = "claranet/monitors/datadog//cloud/aws/rds/aurora/postgresql" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- RDS Aurora PostgreSQL replica lag + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.rds_aurora_postgresql_replica_lag](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [aurora\_replicalag\_enabled](#input\_aurora\_replicalag\_enabled) | Flag to enable RDS Aurora replica lag monitor | `string` | `"true"` | no | +| [aurora\_replicalag\_extra\_tags](#input\_aurora\_replicalag\_extra\_tags) | Extra tags for RDS Aurora replica lag monitor | `list(string)` | `[]` | no | +| [aurora\_replicalag\_message](#input\_aurora\_replicalag\_message) | Custom message for RDS Aurora replica lag monitor | `string` | `""` | no | +| [aurora\_replicalag\_threshold\_critical](#input\_aurora\_replicalag\_threshold\_critical) | Aurora replica lag in milliseconds (critical threshold) | `string` | `"200"` | no | +| [aurora\_replicalag\_threshold\_warning](#input\_aurora\_replicalag\_threshold\_warning) | Aurora replica lag in milliseconds (warning threshold) | `string` | `"100"` | no | +| [aurora\_replicalag\_time\_aggregator](#input\_aurora\_replicalag\_time\_aggregator) | Monitor aggregator for RDS Aurora replica lag [available values: min, max or avg] | `string` | `"min"` | no | +| [aurora\_replicalag\_timeframe](#input\_aurora\_replicalag\_timeframe) | Monitor timeframe for RDS Aurora replica lag monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [rds\_aurora\_postgresql\_replica\_lag\_no\_data\_timeframe](#input\_rds\_aurora\_postgresql\_replica\_lag\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [rds\_aurora\_postgresql\_replica\_lag\_id](#output\_rds\_aurora\_postgresql\_replica\_lag\_id) | id for monitor rds\_aurora\_postgresql\_replica\_lag | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/amazon_rds/](https://docs.datadoghq.com/integrations/amazon_rds/) + +AWS RDS Instance metrics documentation: [https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/MonitoringOverview.html#monitoring-cloudwatch](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/MonitoringOverview.html#monitoring-cloudwatch) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/postgresql/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/postgresql/inputs.tf new file mode 100755 index 0000000..991a67d --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/postgresql/inputs.tf @@ -0,0 +1,93 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "rds_aurora_postgresql_replica_lag_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# AWS RDS Aurora instance specific + +variable "aurora_replicalag_enabled" { + description = "Flag to enable RDS Aurora replica lag monitor" + type = string + default = "true" +} + +variable "aurora_replicalag_extra_tags" { + description = "Extra tags for RDS Aurora replica lag monitor" + type = list(string) + default = [] +} + +variable "aurora_replicalag_message" { + description = "Custom message for RDS Aurora replica lag monitor" + type = string + default = "" +} + +variable "aurora_replicalag_time_aggregator" { + description = "Monitor aggregator for RDS Aurora replica lag [available values: min, max or avg]" + type = string + default = "min" +} + +variable "aurora_replicalag_timeframe" { + description = "Monitor timeframe for RDS Aurora replica lag monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "aurora_replicalag_threshold_warning" { + description = "Aurora replica lag in milliseconds (warning threshold)" + default = "100" +} + +variable "aurora_replicalag_threshold_critical" { + description = "Aurora replica lag in milliseconds (critical threshold)" + default = "200" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/postgresql/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/postgresql/modules.tf new file mode 100755 index 0000000..a5459e6 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/postgresql/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../../../common/filter-tags" + + environment = var.environment + resource = "aws_rds" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/postgresql/monitors-rds-aurora-postgresql.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/postgresql/monitors-rds-aurora-postgresql.tf new file mode 100755 index 0000000..7b43be3 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/postgresql/monitors-rds-aurora-postgresql.tf @@ -0,0 +1,30 @@ +### RDS Aurora Postgresql Replica Lag monitor ### +resource "datadog_monitor" "rds_aurora_postgresql_replica_lag" { + count = var.aurora_replicalag_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] RDS Aurora PostgreSQL replica lag {{#is_alert}}{{{comparator}}} {{threshold}} ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.aurora_replicalag_message, var.message) + type = "query alert" + + query = < ${var.aurora_replicalag_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.aurora_replicalag_threshold_warning + critical = var.aurora_replicalag_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = var.notify_no_data + no_data_timeframe = var.rds_aurora_postgresql_replica_lag_no_data_timeframe + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:rds-aurora-postgresql", "team:claranet", "created-by:terraform"], var.aurora_replicalag_extra_tags) +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/postgresql/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/postgresql/outputs.tf new file mode 100755 index 0000000..118d6bb --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/postgresql/outputs.tf @@ -0,0 +1,5 @@ +output "rds_aurora_postgresql_replica_lag_id" { + description = "id for monitor rds_aurora_postgresql_replica_lag" + value = datadog_monitor.rds_aurora_postgresql_replica_lag.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/postgresql/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/postgresql/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/aurora/postgresql/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/common/MANIFEST.txt b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/common/MANIFEST.txt new file mode 100755 index 0000000..3d83252 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/common/MANIFEST.txt @@ -0,0 +1 @@ +cloud-aws diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/common/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/common/README.md new file mode 100755 index 0000000..daefac8 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/common/README.md @@ -0,0 +1,98 @@ +# CLOUD AWS RDS COMMON DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-rds-common" { + source = "claranet/monitors/datadog//cloud/aws/rds/common" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- RDS instance CPU high +- RDS instance free space +- RDS replica lag + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.rds_cpu_90_15min](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.rds_free_space_low](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.rds_replica_lag](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_enabled](#input\_cpu\_enabled) | Flag to enable RDS CPU usage monitor | `string` | `"true"` | no | +| [cpu\_extra\_tags](#input\_cpu\_extra\_tags) | Extra tags for RDS CPU usage monitor | `list(string)` | `[]` | no | +| [cpu\_message](#input\_cpu\_message) | Custom message for RDS CPU usage monitor | `string` | `""` | no | +| [cpu\_threshold\_critical](#input\_cpu\_threshold\_critical) | CPU usage in percent (critical threshold) | `string` | `"90"` | no | +| [cpu\_threshold\_warning](#input\_cpu\_threshold\_warning) | CPU usage in percent (warning threshold) | `string` | `"80"` | no | +| [cpu\_time\_aggregator](#input\_cpu\_time\_aggregator) | Monitor aggregator for RDS CPU usage [available values: min, max or avg] | `string` | `"min"` | no | +| [cpu\_timeframe](#input\_cpu\_timeframe) | Monitor timeframe for RDS CPU usage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [diskspace\_enabled](#input\_diskspace\_enabled) | Flag to enable RDS free diskspace monitor | `string` | `"true"` | no | +| [diskspace\_extra\_tags](#input\_diskspace\_extra\_tags) | Extra tags for RDS free diskspace monitor | `list(string)` | `[]` | no | +| [diskspace\_message](#input\_diskspace\_message) | Custom message for RDS free diskspace monitor | `string` | `""` | no | +| [diskspace\_threshold\_critical](#input\_diskspace\_threshold\_critical) | Disk free space in percent (critical threshold) | `string` | `"10"` | no | +| [diskspace\_threshold\_warning](#input\_diskspace\_threshold\_warning) | Disk free space in percent (warning threshold) | `string` | `"20"` | no | +| [diskspace\_time\_aggregator](#input\_diskspace\_time\_aggregator) | Monitor aggregator for RDS free diskspace [available values: min, max or avg] | `string` | `"min"` | no | +| [diskspace\_timeframe](#input\_diskspace\_timeframe) | Monitor timeframe for RDS free diskspace [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [rds\_free\_space\_low\_no\_data\_timeframe](#input\_rds\_free\_space\_low\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `30` | no | +| [replicalag\_enabled](#input\_replicalag\_enabled) | Flag to enable RDS replica lag monitor | `string` | `"true"` | no | +| [replicalag\_extra\_tags](#input\_replicalag\_extra\_tags) | Extra tags for RDS replica lag monitor | `list(string)` | `[]` | no | +| [replicalag\_message](#input\_replicalag\_message) | Custom message for RDS replica lag monitor | `string` | `""` | no | +| [replicalag\_threshold\_critical](#input\_replicalag\_threshold\_critical) | replica lag in seconds (critical threshold) | `string` | `"300"` | no | +| [replicalag\_threshold\_warning](#input\_replicalag\_threshold\_warning) | replica lag in seconds (warning threshold) | `string` | `"200"` | no | +| [replicalag\_time\_aggregator](#input\_replicalag\_time\_aggregator) | Monitor aggregator for RDS replica lag [available values: min, max or avg] | `string` | `"min"` | no | +| [replicalag\_timeframe](#input\_replicalag\_timeframe) | Monitor timeframe for RDS replica lag monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [rds\_cpu\_90\_15min\_id](#output\_rds\_cpu\_90\_15min\_id) | id for monitor rds\_cpu\_90\_15min | +| [rds\_free\_space\_low\_id](#output\_rds\_free\_space\_low\_id) | id for monitor rds\_free\_space\_low | +| [rds\_replica\_lag\_id](#output\_rds\_replica\_lag\_id) | id for monitor rds\_replica\_lag | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/amazon_rds/](https://docs.datadoghq.com/integrations/amazon_rds/) + +AWS RDS Instance metrics documentation: [https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/MonitoringOverview.html#monitoring-cloudwatch](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/MonitoringOverview.html#monitoring-cloudwatch) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/common/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/common/inputs.tf new file mode 100755 index 0000000..634d5d9 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/common/inputs.tf @@ -0,0 +1,173 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "rds_free_space_low_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 30 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# AWS RDS instance specific + +variable "cpu_enabled" { + description = "Flag to enable RDS CPU usage monitor" + type = string + default = "true" +} + +variable "cpu_extra_tags" { + description = "Extra tags for RDS CPU usage monitor" + type = list(string) + default = [] +} + +variable "cpu_message" { + description = "Custom message for RDS CPU usage monitor" + type = string + default = "" +} + +variable "cpu_time_aggregator" { + description = "Monitor aggregator for RDS CPU usage [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cpu_timeframe" { + description = "Monitor timeframe for RDS CPU usage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "cpu_threshold_warning" { + description = "CPU usage in percent (warning threshold)" + default = "80" +} + +variable "cpu_threshold_critical" { + description = "CPU usage in percent (critical threshold)" + default = "90" +} + +variable "diskspace_enabled" { + description = "Flag to enable RDS free diskspace monitor" + type = string + default = "true" +} + +variable "diskspace_extra_tags" { + description = "Extra tags for RDS free diskspace monitor" + type = list(string) + default = [] +} + +variable "diskspace_message" { + description = "Custom message for RDS free diskspace monitor" + type = string + default = "" +} + +variable "diskspace_time_aggregator" { + description = "Monitor aggregator for RDS free diskspace [available values: min, max or avg]" + type = string + default = "min" +} + +variable "diskspace_timeframe" { + description = "Monitor timeframe for RDS free diskspace [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "diskspace_threshold_warning" { + description = "Disk free space in percent (warning threshold)" + default = "20" +} + +variable "diskspace_threshold_critical" { + description = "Disk free space in percent (critical threshold)" + default = "10" +} + +variable "replicalag_enabled" { + description = "Flag to enable RDS replica lag monitor" + type = string + default = "true" +} + +variable "replicalag_extra_tags" { + description = "Extra tags for RDS replica lag monitor" + type = list(string) + default = [] +} + +variable "replicalag_message" { + description = "Custom message for RDS replica lag monitor" + type = string + default = "" +} + +variable "replicalag_time_aggregator" { + description = "Monitor aggregator for RDS replica lag [available values: min, max or avg]" + type = string + default = "min" +} + +variable "replicalag_timeframe" { + description = "Monitor timeframe for RDS replica lag monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "replicalag_threshold_warning" { + description = "replica lag in seconds (warning threshold)" + default = "200" +} + +variable "replicalag_threshold_critical" { + description = "replica lag in seconds (critical threshold)" + default = "300" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/common/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/common/modules.tf new file mode 100755 index 0000000..62fbd46 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/common/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../../common/filter-tags" + + environment = var.environment + resource = "aws_rds" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/common/monitors-rds-common.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/common/monitors-rds-common.tf new file mode 100755 index 0000000..cfbc30b --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/common/monitors-rds-common.tf @@ -0,0 +1,91 @@ +### RDS instance CPU monitor ### +resource "datadog_monitor" "rds_cpu_90_15min" { + count = var.cpu_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] RDS instance CPU high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cpu_message, var.message) + type = "query alert" + + query = < ${var.cpu_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.cpu_threshold_warning + critical = var.cpu_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:rds", "team:claranet", "created-by:terraform"], var.cpu_extra_tags) +} + +### RDS instance free space monitor ### +resource "datadog_monitor" "rds_free_space_low" { + count = var.diskspace_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] RDS instance free space {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.diskspace_message, var.message) + type = "query alert" + + query = < ${var.replicalag_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.replicalag_threshold_warning + critical = var.replicalag_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:rds", "team:claranet", "created-by:terraform"], var.replicalag_extra_tags) +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/common/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/common/outputs.tf new file mode 100755 index 0000000..e70b9b6 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/common/outputs.tf @@ -0,0 +1,15 @@ +output "rds_cpu_90_15min_id" { + description = "id for monitor rds_cpu_90_15min" + value = datadog_monitor.rds_cpu_90_15min.*.id +} + +output "rds_free_space_low_id" { + description = "id for monitor rds_free_space_low" + value = datadog_monitor.rds_free_space_low.*.id +} + +output "rds_replica_lag_id" { + description = "id for monitor rds_replica_lag" + value = datadog_monitor.rds_replica_lag.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/common/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/common/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/rds/common/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/sqs/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/sqs/README.md new file mode 100755 index 0000000..050663c --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/sqs/README.md @@ -0,0 +1,85 @@ +# CLOUD AWS SQS DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-sqs" { + source = "claranet/monitors/datadog//cloud/aws/sqs" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- SQS Age of the oldest message +- SQS Visible messages (disabled by default) + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.age_of_oldest_message](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.visible_messages](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [age\_of\_oldest\_message\_enabled](#input\_age\_of\_oldest\_message\_enabled) | Flag to enable Age of Oldest Message monitor | `string` | `"true"` | no | +| [age\_of\_oldest\_message\_extra\_tags](#input\_age\_of\_oldest\_message\_extra\_tags) | Extra tags for Age of Oldest Message monitor | `list(string)` | `[]` | no | +| [age\_of\_oldest\_message\_message](#input\_age\_of\_oldest\_message\_message) | Custom message for Age of Oldest Message monitor | `string` | `""` | no | +| [age\_of\_oldest\_message\_threshold\_critical](#input\_age\_of\_oldest\_message\_threshold\_critical) | Alerting threshold in seconds | `number` | `600` | no | +| [age\_of\_oldest\_message\_threshold\_warning](#input\_age\_of\_oldest\_message\_threshold\_warning) | Warning threshold in seconds | `number` | `300` | no | +| [age\_of\_oldest\_message\_time\_aggregator](#input\_age\_of\_oldest\_message\_time\_aggregator) | Monitor aggregator for Age of Oldest Message [available values: min, max or avg] | `string` | `"min"` | no | +| [age\_of\_oldest\_message\_timeframe](#input\_age\_of\_oldest\_message\_timeframe) | Monitor timeframe for Age of Oldest Message [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_30m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [visible\_messages\_enabled](#input\_visible\_messages\_enabled) | Flag to enable Number of Visible Messages monitor | `string` | `"false"` | no | +| [visible\_messages\_extra\_tags](#input\_visible\_messages\_extra\_tags) | Extra tags for Number of Visible Messages monitor | `list(string)` | `[]` | no | +| [visible\_messages\_message](#input\_visible\_messages\_message) | Custom message for Number of Visible Messages monitor | `string` | `""` | no | +| [visible\_messages\_threshold\_critical](#input\_visible\_messages\_threshold\_critical) | Alerting threshold in number of messages | `number` | `2` | no | +| [visible\_messages\_threshold\_warning](#input\_visible\_messages\_threshold\_warning) | Warning threshold in number of messages | `number` | `1` | no | +| [visible\_messages\_time\_aggregator](#input\_visible\_messages\_time\_aggregator) | Monitor aggregator for Number of Visible Messages [available values: min, max or avg] | `string` | `"min"` | no | +| [visible\_messages\_timeframe](#input\_visible\_messages\_timeframe) | Monitor timeframe for Number of Visible Messages [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_30m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [age\_of\_oldest\_message\_id](#output\_age\_of\_oldest\_message\_id) | id for monitor age\_of\_oldest\_message | +| [visible\_messages\_id](#output\_visible\_messages\_id) | id for monitor visible\_messages | +## Related documentation +* [Datadog Documentation](https://docs.datadoghq.com/integrations/amazon_sqs/) +* [Service Documentation](https://docs.aws.amazon.com/sqs/index.html) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/sqs/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/sqs/inputs.tf new file mode 100755 index 0000000..2f6acf6 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/sqs/inputs.tf @@ -0,0 +1,129 @@ +# Datadog global variables + +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# Datadog monitors variables + +# Approximate Number of Visible Messages +variable "visible_messages_enabled" { + description = "Flag to enable Number of Visible Messages monitor" + type = string + default = "false" +} + +variable "visible_messages_extra_tags" { + description = "Extra tags for Number of Visible Messages monitor" + type = list(string) + default = [] +} + +variable "visible_messages_message" { + description = "Custom message for Number of Visible Messages monitor" + type = string + default = "" +} + +variable "visible_messages_time_aggregator" { + description = "Monitor aggregator for Number of Visible Messages [available values: min, max or avg]" + type = string + default = "min" +} + +variable "visible_messages_timeframe" { + description = "Monitor timeframe for Number of Visible Messages [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_30m" +} + +variable "visible_messages_threshold_critical" { + default = 2 + description = "Alerting threshold in number of messages" +} + +variable "visible_messages_threshold_warning" { + default = 1 + description = "Warning threshold in number of messages" +} + +# Age of the Oldest Message +variable "age_of_oldest_message_enabled" { + description = "Flag to enable Age of Oldest Message monitor" + type = string + default = "true" +} + +variable "age_of_oldest_message_extra_tags" { + description = "Extra tags for Age of Oldest Message monitor" + type = list(string) + default = [] +} + +variable "age_of_oldest_message_message" { + description = "Custom message for Age of Oldest Message monitor" + type = string + default = "" +} + +variable "age_of_oldest_message_time_aggregator" { + description = "Monitor aggregator for Age of Oldest Message [available values: min, max or avg]" + type = string + default = "min" +} + +variable "age_of_oldest_message_timeframe" { + description = "Monitor timeframe for Age of Oldest Message [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_30m" +} + +variable "age_of_oldest_message_threshold_critical" { + default = 600 + description = "Alerting threshold in seconds" +} + +variable "age_of_oldest_message_threshold_warning" { + default = 300 + description = "Warning threshold in seconds" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/sqs/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/sqs/modules.tf new file mode 100755 index 0000000..291a7a5 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/sqs/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "aws_sqs" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/sqs/monitors-sqs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/sqs/monitors-sqs.tf new file mode 100755 index 0000000..794f69b --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/sqs/monitors-sqs.tf @@ -0,0 +1,61 @@ +# Approximate Number of Visible Messages +resource "datadog_monitor" "visible_messages" { + count = var.visible_messages_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] SQS Visible messages {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + type = "metric alert" + message = coalesce(var.visible_messages_message, var.message) + + query = < ${var.visible_messages_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.visible_messages_threshold_critical + warning = var.visible_messages_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:sqs", "team:claranet", "created-by:terraform"], var.visible_messages_extra_tags) +} + +# Age of the Oldest Message +resource "datadog_monitor" "age_of_oldest_message" { + count = var.age_of_oldest_message_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] SQS Age of the oldest message {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + type = "metric alert" + message = coalesce(var.age_of_oldest_message_message, var.message) + + query = < ${var.age_of_oldest_message_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.age_of_oldest_message_threshold_critical + warning = var.age_of_oldest_message_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:aws", "resource:sqs", "team:claranet", "created-by:terraform"], var.age_of_oldest_message_extra_tags) +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/sqs/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/sqs/outputs.tf new file mode 100755 index 0000000..566853e --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/sqs/outputs.tf @@ -0,0 +1,10 @@ +output "age_of_oldest_message_id" { + description = "id for monitor age_of_oldest_message" + value = datadog_monitor.age_of_oldest_message.*.id +} + +output "visible_messages_id" { + description = "id for monitor visible_messages" + value = datadog_monitor.visible_messages.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/sqs/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/sqs/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/sqs/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/vpn/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/vpn/README.md new file mode 100755 index 0000000..09257ac --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/vpn/README.md @@ -0,0 +1,72 @@ +# CLOUD AWS VPN DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-aws-vpn" { + source = "claranet/monitors/datadog//cloud/aws/vpn" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- VPN tunnel down + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.VPN_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags](#input\_filter\_tags) | Tags used for metrics filtering | `string` | `"*"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [vpn\_status\_enabled](#input\_vpn\_status\_enabled) | Flag to enable VPN status monitor | `string` | `"true"` | no | +| [vpn\_status\_extra\_tags](#input\_vpn\_status\_extra\_tags) | Extra tags for VPN status monitor | `list(string)` | `[]` | no | +| [vpn\_status\_message](#input\_vpn\_status\_message) | Custom message for VPN status monitor | `string` | `""` | no | +| [vpn\_status\_no\_data\_timeframe](#input\_vpn\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [vpn\_status\_time\_aggregator](#input\_vpn\_status\_time\_aggregator) | Monitor aggregator for VPN status [available values: min, max or avg] | `string` | `"max"` | no | +| [vpn\_status\_timeframe](#input\_vpn\_status\_timeframe) | Monitor timeframe for VPN status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [VPN\_status\_id](#output\_VPN\_status\_id) | id for monitor VPN\_status | +## Related documentation + +DataDog documentation: [https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/vpn-metricscollected.html](https://docs.datadoghq.com/integrations/amazon_web_services/) + +AWS VPN metrics documentation: [https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/vpn-metricscollected.html](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/vpn-metricscollected.html) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/vpn/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/vpn/inputs.tf new file mode 100755 index 0000000..1d6333a --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/vpn/inputs.tf @@ -0,0 +1,72 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "vpn_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags" { + description = "Tags used for metrics filtering" + default = "*" +} + +variable "vpn_status_enabled" { + description = "Flag to enable VPN status monitor" + type = string + default = "true" +} + +variable "vpn_status_extra_tags" { + description = "Extra tags for VPN status monitor" + type = list(string) + default = [] +} + +variable "vpn_status_message" { + description = "Custom message for VPN status monitor" + type = string + default = "" +} + +variable "vpn_status_time_aggregator" { + description = "Monitor aggregator for VPN status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "vpn_status_timeframe" { + description = "Monitor timeframe for VPN status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/aws/vpn/monitors-vpn.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/vpn/monitors-vpn.tf new file mode 100755 index 0000000..728e846 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/aws/vpn/monitors-vpn.tf @@ -0,0 +1,25 @@ +resource "datadog_monitor" "VPN_status" { + count = var.vpn_status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] VPN tunnel down" + message = coalesce(var.vpn_status_message, var.message) + type = "query alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.apimgt_failed_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.apimgt_other_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.apimgt_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.apimgt_successful_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.apimgt_unauthorized_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [apimgt\_status\_no\_data\_timeframe](#input\_apimgt\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [failed\_requests\_enabled](#input\_failed\_requests\_enabled) | Flag to enable API Management failed requests monitor | `string` | `"true"` | no | +| [failed\_requests\_extra\_tags](#input\_failed\_requests\_extra\_tags) | Extra tags for API Management failed requests monitor | `list(string)` | `[]` | no | +| [failed\_requests\_message](#input\_failed\_requests\_message) | Custom message for API Management failed requests monitor | `string` | `""` | no | +| [failed\_requests\_threshold\_critical](#input\_failed\_requests\_threshold\_critical) | Maximum acceptable percent of failed requests | `number` | `90` | no | +| [failed\_requests\_threshold\_warning](#input\_failed\_requests\_threshold\_warning) | Warning regarding acceptable percent of failed requests | `number` | `50` | no | +| [failed\_requests\_time\_aggregator](#input\_failed\_requests\_time\_aggregator) | Monitor aggregator for API Management failed requests [available values: min, max or avg] | `string` | `"min"` | no | +| [failed\_requests\_timeframe](#input\_failed\_requests\_timeframe) | Monitor timeframe for API Management failed requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a Redis monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [other\_requests\_enabled](#input\_other\_requests\_enabled) | Flag to enable API Management other requests monitor | `string` | `"true"` | no | +| [other\_requests\_extra\_tags](#input\_other\_requests\_extra\_tags) | Extra tags for API Management other requests monitor | `list(string)` | `[]` | no | +| [other\_requests\_message](#input\_other\_requests\_message) | Custom message for API Management other requests monitor | `string` | `""` | no | +| [other\_requests\_threshold\_critical](#input\_other\_requests\_threshold\_critical) | Maximum acceptable percent of other requests | `number` | `90` | no | +| [other\_requests\_threshold\_warning](#input\_other\_requests\_threshold\_warning) | Warning regarding acceptable percent of other requests | `number` | `50` | no | +| [other\_requests\_time\_aggregator](#input\_other\_requests\_time\_aggregator) | Monitor aggregator for API Management other requests [available values: min, max or avg] | `string` | `"min"` | no | +| [other\_requests\_timeframe](#input\_other\_requests\_timeframe) | Monitor timeframe for API Management other requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable API Management status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for API Management status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for API Management status monitor | `string` | `""` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for API Management status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for API Management status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [successful\_requests\_enabled](#input\_successful\_requests\_enabled) | Flag to enable API Management successful requests monitor | `string` | `"true"` | no | +| [successful\_requests\_extra\_tags](#input\_successful\_requests\_extra\_tags) | Extra tags for API Management successful requests monitor | `list(string)` | `[]` | no | +| [successful\_requests\_message](#input\_successful\_requests\_message) | Custom message for API Management successful requests monitor | `string` | `""` | no | +| [successful\_requests\_threshold\_critical](#input\_successful\_requests\_threshold\_critical) | Minimum acceptable percent of successful requests | `number` | `10` | no | +| [successful\_requests\_threshold\_warning](#input\_successful\_requests\_threshold\_warning) | Warning regarding acceptable percent of successful requests | `number` | `30` | no | +| [successful\_requests\_time\_aggregator](#input\_successful\_requests\_time\_aggregator) | Monitor aggregator for API Management successful requests [available values: min, max or avg] | `string` | `"max"` | no | +| [successful\_requests\_timeframe](#input\_successful\_requests\_timeframe) | Monitor timeframe for API Management successful requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [unauthorized\_requests\_enabled](#input\_unauthorized\_requests\_enabled) | Flag to enable API Management unauthorized requests monitor | `string` | `"true"` | no | +| [unauthorized\_requests\_extra\_tags](#input\_unauthorized\_requests\_extra\_tags) | Extra tags for API Management unauthorized requests monitor | `list(string)` | `[]` | no | +| [unauthorized\_requests\_message](#input\_unauthorized\_requests\_message) | Custom message for API Management unauthorized requests monitor | `string` | `""` | no | +| [unauthorized\_requests\_threshold\_critical](#input\_unauthorized\_requests\_threshold\_critical) | Maximum acceptable percent of unauthorized requests | `number` | `90` | no | +| [unauthorized\_requests\_threshold\_warning](#input\_unauthorized\_requests\_threshold\_warning) | Warning regarding acceptable percent of unauthorized requests | `number` | `50` | no | +| [unauthorized\_requests\_time\_aggregator](#input\_unauthorized\_requests\_time\_aggregator) | Monitor aggregator for API Management unauthorized requests [available values: min, max or avg] | `string` | `"min"` | no | +| [unauthorized\_requests\_timeframe](#input\_unauthorized\_requests\_timeframe) | Monitor timeframe for API Management unauthorized requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [apimgt\_failed\_requests\_id](#output\_apimgt\_failed\_requests\_id) | id for monitor apimgt\_failed\_requests | +| [apimgt\_other\_requests\_id](#output\_apimgt\_other\_requests\_id) | id for monitor apimgt\_other\_requests | +| [apimgt\_status\_id](#output\_apimgt\_status\_id) | id for monitor apimgt\_status | +| [apimgt\_successful\_requests\_id](#output\_apimgt\_successful\_requests\_id) | id for monitor apimgt\_successful\_requests | +| [apimgt\_unauthorized\_requests\_id](#output\_apimgt\_unauthorized\_requests\_id) | id for monitor apimgt\_unauthorized\_requests | +## Related documentation + +Azure API Management metrics documentation: [https://docs.microsoft.com/en-us/azure/api-management/api-management-howto-use-azure-monitor](https://docs.microsoft.com/en-us/azure/api-management/api-management-howto-use-azure-monitor) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/apimanagement/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/apimanagement/inputs.tf new file mode 100755 index 0000000..da1fe59 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/apimanagement/inputs.tf @@ -0,0 +1,244 @@ +# Global Terraform +variable "environment" { + description = "Architecture environment" + type = string +} + +# Global DataDog +variable "message" { + description = "Message sent when a Redis monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "apimgt_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Azure API Management specific + +variable "status_enabled" { + description = "Flag to enable API Management status monitor" + type = string + default = "true" +} + +variable "status_extra_tags" { + description = "Extra tags for API Management status monitor" + type = list(string) + default = [] +} + +variable "status_message" { + description = "Custom message for API Management status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for API Management status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for API Management status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_requests_enabled" { + description = "Flag to enable API Management failed requests monitor" + type = string + default = "true" +} + +variable "failed_requests_extra_tags" { + description = "Extra tags for API Management failed requests monitor" + type = list(string) + default = [] +} + +variable "failed_requests_message" { + description = "Custom message for API Management failed requests monitor" + type = string + default = "" +} + +variable "failed_requests_time_aggregator" { + description = "Monitor aggregator for API Management failed requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "failed_requests_timeframe" { + description = "Monitor timeframe for API Management failed requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_requests_threshold_critical" { + description = "Maximum acceptable percent of failed requests" + default = 90 +} + +variable "failed_requests_threshold_warning" { + description = "Warning regarding acceptable percent of failed requests" + default = 50 +} + +variable "other_requests_enabled" { + description = "Flag to enable API Management other requests monitor" + type = string + default = "true" +} + +variable "other_requests_extra_tags" { + description = "Extra tags for API Management other requests monitor" + type = list(string) + default = [] +} + +variable "other_requests_message" { + description = "Custom message for API Management other requests monitor" + type = string + default = "" +} + +variable "other_requests_time_aggregator" { + description = "Monitor aggregator for API Management other requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "other_requests_timeframe" { + description = "Monitor timeframe for API Management other requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "other_requests_threshold_critical" { + description = "Maximum acceptable percent of other requests" + default = 90 +} + +variable "other_requests_threshold_warning" { + description = "Warning regarding acceptable percent of other requests" + default = 50 +} + +variable "unauthorized_requests_enabled" { + description = "Flag to enable API Management unauthorized requests monitor" + type = string + default = "true" +} + +variable "unauthorized_requests_extra_tags" { + description = "Extra tags for API Management unauthorized requests monitor" + type = list(string) + default = [] +} + +variable "unauthorized_requests_message" { + description = "Custom message for API Management unauthorized requests monitor" + type = string + default = "" +} + +variable "unauthorized_requests_time_aggregator" { + description = "Monitor aggregator for API Management unauthorized requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "unauthorized_requests_timeframe" { + description = "Monitor timeframe for API Management unauthorized requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "unauthorized_requests_threshold_critical" { + description = "Maximum acceptable percent of unauthorized requests" + default = 90 +} + +variable "unauthorized_requests_threshold_warning" { + description = "Warning regarding acceptable percent of unauthorized requests" + default = 50 +} + +variable "successful_requests_enabled" { + description = "Flag to enable API Management successful requests monitor" + type = string + default = "true" +} + +variable "successful_requests_extra_tags" { + description = "Extra tags for API Management successful requests monitor" + type = list(string) + default = [] +} + +variable "successful_requests_message" { + description = "Custom message for API Management successful requests monitor" + type = string + default = "" +} + +variable "successful_requests_time_aggregator" { + description = "Monitor aggregator for API Management successful requests [available values: min, max or avg]" + type = string + default = "max" +} + +variable "successful_requests_timeframe" { + description = "Monitor timeframe for API Management successful requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "successful_requests_threshold_critical" { + description = "Minimum acceptable percent of successful requests" + default = 10 +} + +variable "successful_requests_threshold_warning" { + description = "Warning regarding acceptable percent of successful requests" + default = 30 +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/apimanagement/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/apimanagement/modules.tf new file mode 100755 index 0000000..758b72e --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/apimanagement/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_apimanagement" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/apimanagement/monitors-azure-apimanagement.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/apimanagement/monitors-azure-apimanagement.tf new file mode 100755 index 0000000..fe4e060 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/apimanagement/monitors-azure-apimanagement.tf @@ -0,0 +1,154 @@ +resource "datadog_monitor" "apimgt_status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] API Management is down" + message = coalesce(var.status_message, var.message) + type = "metric alert" + + query = < ${var.failed_requests_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.failed_requests_threshold_critical + warning = var.failed_requests_threshold_warning + } + + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + notify_no_data = false + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:apimanagement", "team:claranet", "created-by:terraform"], var.failed_requests_extra_tags) +} + +resource "datadog_monitor" "apimgt_other_requests" { + count = var.other_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] API Management too many other requests {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.other_requests_message, var.message) + type = "query alert" + + query = < ${var.other_requests_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.other_requests_threshold_critical + warning = var.other_requests_threshold_warning + } + + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + notify_no_data = false + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:apimanagement", "team:claranet", "created-by:terraform"], var.other_requests_extra_tags) +} + +resource "datadog_monitor" "apimgt_unauthorized_requests" { + count = var.unauthorized_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] API Management too many unauthorized requests {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.unauthorized_requests_message, var.message) + type = "query alert" + + query = < ${var.unauthorized_requests_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.unauthorized_requests_threshold_critical + warning = var.unauthorized_requests_threshold_warning + } + + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + notify_no_data = false + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:apimanagement", "team:claranet", "created-by:terraform"], var.unauthorized_requests_extra_tags) +} + +resource "datadog_monitor" "apimgt_successful_requests" { + count = var.successful_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] API Management successful requests rate too low {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.successful_requests_message, var.message) + type = "query alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | +| [filter-tags-4xx-error](#module\_filter-tags-4xx-error) | ../../../common/filter-tags | n/a | +| [filter-tags-5xx-error](#module\_filter-tags-5xx-error) | ../../../common/filter-tags | n/a | +| [filter-tags-backend-4xx-error](#module\_filter-tags-backend-4xx-error) | ../../../common/filter-tags | n/a | +| [filter-tags-backend-5xx-error](#module\_filter-tags-backend-5xx-error) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.appgateway_backend_connect_time](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appgateway_backend_http_4xx_errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appgateway_backend_http_5xx_errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appgateway_failed_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appgateway_healthy_host_ratio](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appgateway_http_4xx_errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appgateway_http_5xx_errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appgateway_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.total_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [appgateway\_backend\_connect\_time\_enabled](#input\_appgateway\_backend\_connect\_time\_enabled) | Flag to enable App Gateway backend\_connect\_time monitor | `string` | `"true"` | no | +| [appgateway\_backend\_connect\_time\_extra\_tags](#input\_appgateway\_backend\_connect\_time\_extra\_tags) | Extra tags for App Gateway backend\_connect\_time monitor | `list(string)` | `[]` | no | +| [appgateway\_backend\_connect\_time\_message](#input\_appgateway\_backend\_connect\_time\_message) | Custom message for App Gateway backend\_connect\_time monitor | `string` | `""` | no | +| [appgateway\_backend\_connect\_time\_threshold\_critical](#input\_appgateway\_backend\_connect\_time\_threshold\_critical) | Maximum critical backend\_connect\_time errors in milliseconds | `number` | `50` | no | +| [appgateway\_backend\_connect\_time\_threshold\_warning](#input\_appgateway\_backend\_connect\_time\_threshold\_warning) | Warning regarding backend\_connect\_time errors in milliseconds | `number` | `40` | no | +| [appgateway\_backend\_connect\_time\_time\_aggregator](#input\_appgateway\_backend\_connect\_time\_time\_aggregator) | Monitor aggregator for App Gateway backend\_connect\_time [available values: min, max or avg] | `string` | `"max"` | no | +| [appgateway\_backend\_connect\_time\_timeframe](#input\_appgateway\_backend\_connect\_time\_timeframe) | Monitor timeframe for App Gateway backend\_connect\_time [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [appgateway\_backend\_http\_4xx\_errors\_enabled](#input\_appgateway\_backend\_http\_4xx\_errors\_enabled) | Flag to enable App Gateway http 4xx errors monitor | `string` | `"true"` | no | +| [appgateway\_backend\_http\_4xx\_errors\_extra\_tags](#input\_appgateway\_backend\_http\_4xx\_errors\_extra\_tags) | Extra tags for App Gateway http 4xx errors monitor | `list(string)` | `[]` | no | +| [appgateway\_backend\_http\_4xx\_errors\_message](#input\_appgateway\_backend\_http\_4xx\_errors\_message) | Custom message for App Gateway http 4xx errors monitor | `string` | `""` | no | +| [appgateway\_backend\_http\_4xx\_errors\_threshold\_critical](#input\_appgateway\_backend\_http\_4xx\_errors\_threshold\_critical) | Minimum critical acceptable percent of 4xx error | `number` | `95` | no | +| [appgateway\_backend\_http\_4xx\_errors\_threshold\_warning](#input\_appgateway\_backend\_http\_4xx\_errors\_threshold\_warning) | Warning regarding acceptable percent of 4xx error | `number` | `80` | no | +| [appgateway\_backend\_http\_4xx\_errors\_time\_aggregator](#input\_appgateway\_backend\_http\_4xx\_errors\_time\_aggregator) | Monitor aggregator for App Gateway http 4xx errors [available values: min, max or avg] | `string` | `"max"` | no | +| [appgateway\_backend\_http\_4xx\_errors\_timeframe](#input\_appgateway\_backend\_http\_4xx\_errors\_timeframe) | Monitor timeframe for App Gateway http 4xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [appgateway\_backend\_http\_5xx\_errors\_enabled](#input\_appgateway\_backend\_http\_5xx\_errors\_enabled) | Flag to enable App Gateway http 5xx errors monitor | `string` | `"true"` | no | +| [appgateway\_backend\_http\_5xx\_errors\_extra\_tags](#input\_appgateway\_backend\_http\_5xx\_errors\_extra\_tags) | Extra tags for App Gateway http 5xx errors monitor | `list(string)` | `[]` | no | +| [appgateway\_backend\_http\_5xx\_errors\_message](#input\_appgateway\_backend\_http\_5xx\_errors\_message) | Custom message for App Gateway http 5xx errors monitor | `string` | `""` | no | +| [appgateway\_backend\_http\_5xx\_errors\_threshold\_critical](#input\_appgateway\_backend\_http\_5xx\_errors\_threshold\_critical) | Minimum critical acceptable percent of 5xx error | `number` | `95` | no | +| [appgateway\_backend\_http\_5xx\_errors\_threshold\_warning](#input\_appgateway\_backend\_http\_5xx\_errors\_threshold\_warning) | Warning regarding acceptable percent of 5xx error | `number` | `80` | no | +| [appgateway\_backend\_http\_5xx\_errors\_time\_aggregator](#input\_appgateway\_backend\_http\_5xx\_errors\_time\_aggregator) | Monitor aggregator for App Gateway http 5xx errors [available values: min, max or avg] | `string` | `"max"` | no | +| [appgateway\_backend\_http\_5xx\_errors\_timeframe](#input\_appgateway\_backend\_http\_5xx\_errors\_timeframe) | Monitor timeframe for App Gateway http 5xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [appgateway\_failed\_requests\_enabled](#input\_appgateway\_failed\_requests\_enabled) | Flag to enable App Gateway failed requests monitor | `string` | `"true"` | no | +| [appgateway\_failed\_requests\_extra\_tags](#input\_appgateway\_failed\_requests\_extra\_tags) | Extra tags for App Gateway failed requests monitor | `list(string)` | `[]` | no | +| [appgateway\_failed\_requests\_message](#input\_appgateway\_failed\_requests\_message) | Custom message for App Gateway failed requests monitor | `string` | `""` | no | +| [appgateway\_failed\_requests\_threshold\_critical](#input\_appgateway\_failed\_requests\_threshold\_critical) | Maximum critical acceptable percent of failed errors | `number` | `95` | no | +| [appgateway\_failed\_requests\_threshold\_warning](#input\_appgateway\_failed\_requests\_threshold\_warning) | Warning regarding acceptable percent of failed errors | `number` | `80` | no | +| [appgateway\_failed\_requests\_time\_aggregator](#input\_appgateway\_failed\_requests\_time\_aggregator) | Monitor aggregator for App Gateway failed requests [available values: min, max or avg] | `string` | `"min"` | no | +| [appgateway\_failed\_requests\_timeframe](#input\_appgateway\_failed\_requests\_timeframe) | Monitor timeframe for App Gateway failed requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [appgateway\_http\_4xx\_errors\_enabled](#input\_appgateway\_http\_4xx\_errors\_enabled) | Flag to enable App Gateway http 4xx errors monitor | `string` | `"true"` | no | +| [appgateway\_http\_4xx\_errors\_extra\_tags](#input\_appgateway\_http\_4xx\_errors\_extra\_tags) | Extra tags for App Gateway http 4xx errors monitor | `list(string)` | `[]` | no | +| [appgateway\_http\_4xx\_errors\_message](#input\_appgateway\_http\_4xx\_errors\_message) | Custom message for App Gateway http 4xx errors monitor | `string` | `""` | no | +| [appgateway\_http\_4xx\_errors\_threshold\_critical](#input\_appgateway\_http\_4xx\_errors\_threshold\_critical) | Maximum critical acceptable percent of 4xx error | `number` | `95` | no | +| [appgateway\_http\_4xx\_errors\_threshold\_warning](#input\_appgateway\_http\_4xx\_errors\_threshold\_warning) | Warning regarding acceptable percent of 4xx error | `number` | `80` | no | +| [appgateway\_http\_4xx\_errors\_time\_aggregator](#input\_appgateway\_http\_4xx\_errors\_time\_aggregator) | Monitor aggregator for App Gateway http 4xx errors [available values: min, max or avg] | `string` | `"max"` | no | +| [appgateway\_http\_4xx\_errors\_timeframe](#input\_appgateway\_http\_4xx\_errors\_timeframe) | Monitor timeframe for App Gateway http 4xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [appgateway\_http\_5xx\_errors\_enabled](#input\_appgateway\_http\_5xx\_errors\_enabled) | Flag to enable App Gateway http 5xx errors monitor | `string` | `"true"` | no | +| [appgateway\_http\_5xx\_errors\_extra\_tags](#input\_appgateway\_http\_5xx\_errors\_extra\_tags) | Extra tags for App Gateway http 5xx errors monitor | `list(string)` | `[]` | no | +| [appgateway\_http\_5xx\_errors\_message](#input\_appgateway\_http\_5xx\_errors\_message) | Custom message for App Gateway http 5xx errors monitor | `string` | `""` | no | +| [appgateway\_http\_5xx\_errors\_threshold\_critical](#input\_appgateway\_http\_5xx\_errors\_threshold\_critical) | Maximum critical acceptable percent of 5xx error | `number` | `95` | no | +| [appgateway\_http\_5xx\_errors\_threshold\_warning](#input\_appgateway\_http\_5xx\_errors\_threshold\_warning) | Warning regarding acceptable percent of 5xx error | `number` | `80` | no | +| [appgateway\_http\_5xx\_errors\_time\_aggregator](#input\_appgateway\_http\_5xx\_errors\_time\_aggregator) | Monitor aggregator for App Gateway http 5xx errors [available values: min, max or avg] | `string` | `"max"` | no | +| [appgateway\_http\_5xx\_errors\_timeframe](#input\_appgateway\_http\_5xx\_errors\_timeframe) | Monitor timeframe for App Gateway http 5xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [appgateway\_status\_no\_data\_timeframe](#input\_appgateway\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [appgateway\_unhealthy\_host\_ratio\_enabled](#input\_appgateway\_unhealthy\_host\_ratio\_enabled) | Flag to enable App Gateway unhealthy host ratio monitor | `string` | `"true"` | no | +| [appgateway\_unhealthy\_host\_ratio\_extra\_tags](#input\_appgateway\_unhealthy\_host\_ratio\_extra\_tags) | Extra tags for App Gateway unhealthy host ratio monitor | `list(string)` | `[]` | no | +| [appgateway\_unhealthy\_host\_ratio\_message](#input\_appgateway\_unhealthy\_host\_ratio\_message) | Custom message for App Gateway unhealthy host ratio monitor | `string` | `""` | no | +| [appgateway\_unhealthy\_host\_ratio\_threshold\_critical](#input\_appgateway\_unhealthy\_host\_ratio\_threshold\_critical) | Maximum critical acceptable ratio of unhealthy host | `number` | `75` | no | +| [appgateway\_unhealthy\_host\_ratio\_threshold\_warning](#input\_appgateway\_unhealthy\_host\_ratio\_threshold\_warning) | Warning regarding acceptable ratio of unhealthy host | `number` | `50` | no | +| [appgateway\_unhealthy\_host\_ratio\_time\_aggregator](#input\_appgateway\_unhealthy\_host\_ratio\_time\_aggregator) | Monitor aggregator for App Gateway unhealthy host ratio [available values: min, max or avg] | `string` | `"max"` | no | +| [appgateway\_unhealthy\_host\_ratio\_timeframe](#input\_appgateway\_unhealthy\_host\_ratio\_timeframe) | Monitor timeframe for App Gateway unhealthy host ratio [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable App Gateway status | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for App Gateway status | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for App Gateway status | `string` | `""` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for App Gateway status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for App Gateway status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [total\_requests\_enabled](#input\_total\_requests\_enabled) | Flag to enable App Gateway current connections monitor | `string` | `"true"` | no | +| [total\_requests\_extra\_tags](#input\_total\_requests\_extra\_tags) | Extra tags for App Gateway current connections monitor | `list(string)` | `[]` | no | +| [total\_requests\_message](#input\_total\_requests\_message) | Custom message for App Gateway current connections monitor | `string` | `""` | no | +| [total\_requests\_time\_aggregator](#input\_total\_requests\_time\_aggregator) | Monitor aggregator for App Gateway current connections [available values: min, max or avg] | `string` | `"max"` | no | +| [total\_requests\_timeframe](#input\_total\_requests\_timeframe) | Monitor timeframe for App Gateway current connections [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [appgateway\_backend\_connect\_time\_id](#output\_appgateway\_backend\_connect\_time\_id) | id for monitor appgateway\_backend\_connect\_time | +| [appgateway\_backend\_http\_4xx\_errors\_id](#output\_appgateway\_backend\_http\_4xx\_errors\_id) | id for monitor appgateway\_backend\_http\_4xx\_errors | +| [appgateway\_backend\_http\_5xx\_errors\_id](#output\_appgateway\_backend\_http\_5xx\_errors\_id) | id for monitor appgateway\_backend\_http\_5xx\_errors | +| [appgateway\_failed\_requests\_id](#output\_appgateway\_failed\_requests\_id) | id for monitor appgateway\_failed\_requests | +| [appgateway\_healthy\_host\_ratio\_id](#output\_appgateway\_healthy\_host\_ratio\_id) | id for monitor appgateway\_healthy\_host\_ratio | +| [appgateway\_http\_4xx\_errors\_id](#output\_appgateway\_http\_4xx\_errors\_id) | id for monitor appgateway\_http\_4xx\_errors | +| [appgateway\_http\_5xx\_errors\_id](#output\_appgateway\_http\_5xx\_errors\_id) | id for monitor appgateway\_http\_5xx\_errors | +| [appgateway\_status\_id](#output\_appgateway\_status\_id) | id for monitor appgateway\_status | +| [total\_requests\_id](#output\_total\_requests\_id) | id for monitor total\_requests | +## Related documentation + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-gateway/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-gateway/inputs.tf new file mode 100755 index 0000000..2d37818 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-gateway/inputs.tf @@ -0,0 +1,400 @@ +# Azure App Gateway global variables +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "appgateway_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# Azure App Gateway specific variables +# Monitoring App Gateway status +variable "status_enabled" { + description = "Flag to enable App Gateway status" + type = string + default = "true" +} + +variable "status_extra_tags" { + description = "Extra tags for App Gateway status" + type = list(string) + default = [] +} + +variable "status_message" { + description = "Custom message for App Gateway status" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for App Gateway status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for App Gateway status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +# Monitoring App Gateway total_requests +variable "total_requests_enabled" { + description = "Flag to enable App Gateway current connections monitor" + type = string + default = "true" +} + +variable "total_requests_extra_tags" { + description = "Extra tags for App Gateway current connections monitor" + type = list(string) + default = [] +} + +variable "total_requests_message" { + description = "Custom message for App Gateway current connections monitor" + type = string + default = "" +} + +variable "total_requests_time_aggregator" { + description = "Monitor aggregator for App Gateway current connections [available values: min, max or avg]" + type = string + default = "max" +} + +variable "total_requests_timeframe" { + description = "Monitor timeframe for App Gateway current connections [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +# Monitoring App Gateway failed_requests +variable "appgateway_backend_connect_time_enabled" { + description = "Flag to enable App Gateway backend_connect_time monitor" + type = string + default = "true" +} + +variable "appgateway_backend_connect_time_extra_tags" { + description = "Extra tags for App Gateway backend_connect_time monitor" + type = list(string) + default = [] +} + +variable "appgateway_backend_connect_time_message" { + description = "Custom message for App Gateway backend_connect_time monitor" + type = string + default = "" +} + +variable "appgateway_backend_connect_time_time_aggregator" { + description = "Monitor aggregator for App Gateway backend_connect_time [available values: min, max or avg]" + type = string + default = "max" +} + +variable "appgateway_backend_connect_time_timeframe" { + description = "Monitor timeframe for App Gateway backend_connect_time [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "appgateway_backend_connect_time_threshold_critical" { + default = 50 + description = "Maximum critical backend_connect_time errors in milliseconds" +} + +variable "appgateway_backend_connect_time_threshold_warning" { + default = 40 + description = "Warning regarding backend_connect_time errors in milliseconds" +} + +# Monitoring App Gateway failed_requests +variable "appgateway_failed_requests_enabled" { + description = "Flag to enable App Gateway failed requests monitor" + type = string + default = "true" +} + +variable "appgateway_failed_requests_extra_tags" { + description = "Extra tags for App Gateway failed requests monitor" + type = list(string) + default = [] +} + +variable "appgateway_failed_requests_message" { + description = "Custom message for App Gateway failed requests monitor" + type = string + default = "" +} + +variable "appgateway_failed_requests_time_aggregator" { + description = "Monitor aggregator for App Gateway failed requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "appgateway_failed_requests_timeframe" { + description = "Monitor timeframe for App Gateway failed requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "appgateway_failed_requests_threshold_critical" { + default = 95 + description = "Maximum critical acceptable percent of failed errors" +} + +variable "appgateway_failed_requests_threshold_warning" { + default = 80 + description = "Warning regarding acceptable percent of failed errors" +} + +# Monitoring App Gateway unhealthy_host_ratio +variable "appgateway_unhealthy_host_ratio_enabled" { + description = "Flag to enable App Gateway unhealthy host ratio monitor" + type = string + default = "true" +} + +variable "appgateway_unhealthy_host_ratio_extra_tags" { + description = "Extra tags for App Gateway unhealthy host ratio monitor" + type = list(string) + default = [] +} + +variable "appgateway_unhealthy_host_ratio_message" { + description = "Custom message for App Gateway unhealthy host ratio monitor" + type = string + default = "" +} + +variable "appgateway_unhealthy_host_ratio_time_aggregator" { + description = "Monitor aggregator for App Gateway unhealthy host ratio [available values: min, max or avg]" + type = string + default = "max" +} + +variable "appgateway_unhealthy_host_ratio_timeframe" { + description = "Monitor timeframe for App Gateway unhealthy host ratio [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "appgateway_unhealthy_host_ratio_threshold_critical" { + default = 75 + description = "Maximum critical acceptable ratio of unhealthy host" +} + +variable "appgateway_unhealthy_host_ratio_threshold_warning" { + default = 50 + description = "Warning regarding acceptable ratio of unhealthy host" +} + +# Monitoring App Gateway response_status 4xx +variable "appgateway_http_4xx_errors_enabled" { + description = "Flag to enable App Gateway http 4xx errors monitor" + type = string + default = "true" +} + +variable "appgateway_http_4xx_errors_extra_tags" { + description = "Extra tags for App Gateway http 4xx errors monitor" + type = list(string) + default = [] +} + +variable "appgateway_http_4xx_errors_message" { + description = "Custom message for App Gateway http 4xx errors monitor" + type = string + default = "" +} + +variable "appgateway_http_4xx_errors_time_aggregator" { + description = "Monitor aggregator for App Gateway http 4xx errors [available values: min, max or avg]" + type = string + default = "max" +} + +variable "appgateway_http_4xx_errors_timeframe" { + description = "Monitor timeframe for App Gateway http 4xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "appgateway_http_4xx_errors_threshold_critical" { + default = 95 + description = "Maximum critical acceptable percent of 4xx error" +} + +variable "appgateway_http_4xx_errors_threshold_warning" { + default = 80 + description = "Warning regarding acceptable percent of 4xx error" +} + +# Monitoring App Gateway response_status 5xx +variable "appgateway_http_5xx_errors_enabled" { + description = "Flag to enable App Gateway http 5xx errors monitor" + type = string + default = "true" +} + +variable "appgateway_http_5xx_errors_extra_tags" { + description = "Extra tags for App Gateway http 5xx errors monitor" + type = list(string) + default = [] +} + +variable "appgateway_http_5xx_errors_message" { + description = "Custom message for App Gateway http 5xx errors monitor" + type = string + default = "" +} + +variable "appgateway_http_5xx_errors_time_aggregator" { + description = "Monitor aggregator for App Gateway http 5xx errors [available values: min, max or avg]" + type = string + default = "max" +} + +variable "appgateway_http_5xx_errors_timeframe" { + description = "Monitor timeframe for App Gateway http 5xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "appgateway_http_5xx_errors_threshold_critical" { + default = 95 + description = "Maximum critical acceptable percent of 5xx error" +} + +variable "appgateway_http_5xx_errors_threshold_warning" { + default = 80 + description = "Warning regarding acceptable percent of 5xx error" +} + +# Monitoring App Gateway Backend response_status 4xx +variable "appgateway_backend_http_4xx_errors_enabled" { + description = "Flag to enable App Gateway http 4xx errors monitor" + type = string + default = "true" +} + +variable "appgateway_backend_http_4xx_errors_extra_tags" { + description = "Extra tags for App Gateway http 4xx errors monitor" + type = list(string) + default = [] +} + +variable "appgateway_backend_http_4xx_errors_message" { + description = "Custom message for App Gateway http 4xx errors monitor" + type = string + default = "" +} + +variable "appgateway_backend_http_4xx_errors_time_aggregator" { + description = "Monitor aggregator for App Gateway http 4xx errors [available values: min, max or avg]" + type = string + default = "max" +} + +variable "appgateway_backend_http_4xx_errors_timeframe" { + description = "Monitor timeframe for App Gateway http 4xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "appgateway_backend_http_4xx_errors_threshold_critical" { + default = 95 + description = "Minimum critical acceptable percent of 4xx error" +} + +variable "appgateway_backend_http_4xx_errors_threshold_warning" { + default = 80 + description = "Warning regarding acceptable percent of 4xx error" +} + +# Monitoring App Gateway Backend response_status 5xx +variable "appgateway_backend_http_5xx_errors_enabled" { + description = "Flag to enable App Gateway http 5xx errors monitor" + type = string + default = "true" +} + +variable "appgateway_backend_http_5xx_errors_extra_tags" { + description = "Extra tags for App Gateway http 5xx errors monitor" + type = list(string) + default = [] +} + +variable "appgateway_backend_http_5xx_errors_message" { + description = "Custom message for App Gateway http 5xx errors monitor" + type = string + default = "" +} + +variable "appgateway_backend_http_5xx_errors_time_aggregator" { + description = "Monitor aggregator for App Gateway http 5xx errors [available values: min, max or avg]" + type = string + default = "max" +} + +variable "appgateway_backend_http_5xx_errors_timeframe" { + description = "Monitor timeframe for App Gateway http 5xx errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "appgateway_backend_http_5xx_errors_threshold_critical" { + default = 95 + description = "Minimum critical acceptable percent of 5xx error" +} + +variable "appgateway_backend_http_5xx_errors_threshold_warning" { + default = 80 + description = "Warning regarding acceptable percent of 5xx error" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-gateway/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-gateway/modules.tf new file mode 100755 index 0000000..12b0c58 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-gateway/modules.tf @@ -0,0 +1,53 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_app-gateway" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + +module "filter-tags-4xx-error" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_app-gateway" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["httpstatusgroup:4xx"] +} + +module "filter-tags-5xx-error" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_app-gateway" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["httpstatusgroup:5xx"] +} + +module "filter-tags-backend-4xx-error" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_app-gateway" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["httpstatusgroup:4xx"] +} + +module "filter-tags-backend-5xx-error" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_app-gateway" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["httpstatusgroup:5xx"] +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-gateway/monitors-app-gateway.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-gateway/monitors-app-gateway.tf new file mode 100755 index 0000000..7680ac2 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-gateway/monitors-app-gateway.tf @@ -0,0 +1,267 @@ +# Monitoring App Gateway status +resource "datadog_monitor" "appgateway_status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Gateway is down" + message = coalesce(var.status_message, var.message) + type = "metric alert" + + query = < ${var.appgateway_backend_connect_time_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.appgateway_backend_connect_time_threshold_critical + warning = var.appgateway_backend_connect_time_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:app-gateway", "team:claranet", "created-by:terraform"], var.appgateway_backend_connect_time_extra_tags) +} + +# Monitoring App Gateway failed_requests +resource "datadog_monitor" "appgateway_failed_requests" { + count = var.appgateway_failed_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Gateway failed requests {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.appgateway_failed_requests_message, var.message) + type = "query alert" + + query = < ${var.appgateway_failed_requests_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.appgateway_failed_requests_threshold_critical + warning = var.appgateway_failed_requests_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:app-gateway", "team:claranet", "created-by:terraform"], var.appgateway_failed_requests_extra_tags) +} + +# Monitoring App Gateway unhealthy_host_ratio +resource "datadog_monitor" "appgateway_healthy_host_ratio" { + count = var.appgateway_unhealthy_host_ratio_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Gateway backend unhealthy host ratio is too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.appgateway_unhealthy_host_ratio_message, var.message) + type = "query alert" + + query = < ${var.appgateway_unhealthy_host_ratio_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.appgateway_unhealthy_host_ratio_threshold_critical + warning = var.appgateway_unhealthy_host_ratio_threshold_warning + } + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:app-gateway", "team:claranet", "created-by:terraform"], var.appgateway_unhealthy_host_ratio_extra_tags) +} + +# Monitoring App Gateway response_status 4xx +resource "datadog_monitor" "appgateway_http_4xx_errors" { + count = var.appgateway_http_4xx_errors_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Gateway HTTP 4xx errors rate is too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.appgateway_http_4xx_errors_message, var.message) + type = "query alert" + + query = < ${var.appgateway_http_4xx_errors_threshold_critical} +EOQ + + + monitor_thresholds { + warning = var.appgateway_http_4xx_errors_threshold_warning + critical = var.appgateway_http_4xx_errors_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 1 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:app-gateway", "team:claranet", "created-by:terraform"], var.appgateway_http_4xx_errors_extra_tags) +} + +# Monitoring App Gateway response_status 5xx +resource "datadog_monitor" "appgateway_http_5xx_errors" { + count = var.appgateway_http_5xx_errors_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Gateway HTTP 5xx errors rate is too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.appgateway_http_5xx_errors_message, var.message) + type = "query alert" + + query = < ${var.appgateway_http_5xx_errors_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.appgateway_http_5xx_errors_threshold_warning + critical = var.appgateway_http_5xx_errors_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 1 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:app-gateway", "team:claranet", "created-by:terraform"], var.appgateway_http_5xx_errors_extra_tags) +} + +# Monitoring App Gateway Backend response_status 4xx +resource "datadog_monitor" "appgateway_backend_http_4xx_errors" { + count = var.appgateway_backend_http_4xx_errors_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Gateway backend HTTP 4xx errors rate is too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.appgateway_backend_http_4xx_errors_message, var.message) + type = "query alert" + + query = < ${var.appgateway_backend_http_4xx_errors_threshold_critical} +EOQ + + + monitor_thresholds { + warning = var.appgateway_backend_http_4xx_errors_threshold_warning + critical = var.appgateway_backend_http_4xx_errors_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 1 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:app-gateway", "team:claranet", "created-by:terraform"], var.appgateway_backend_http_4xx_errors_extra_tags) +} + +# Monitoring App Gateway Backend response_status 5xx +resource "datadog_monitor" "appgateway_backend_http_5xx_errors" { + count = var.appgateway_backend_http_5xx_errors_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Gateway backend HTTP 5xx errors rate is too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.appgateway_backend_http_5xx_errors_message, var.message) + type = "query alert" + + query = < ${var.appgateway_backend_http_5xx_errors_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.appgateway_backend_http_5xx_errors_threshold_warning + critical = var.appgateway_backend_http_5xx_errors_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 1 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:app-gateway", "team:claranet", "created-by:terraform"], var.appgateway_backend_http_5xx_errors_extra_tags) +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-gateway/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-gateway/outputs.tf new file mode 100755 index 0000000..e291598 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-gateway/outputs.tf @@ -0,0 +1,45 @@ +output "appgateway_backend_connect_time_id" { + description = "id for monitor appgateway_backend_connect_time" + value = datadog_monitor.appgateway_backend_connect_time.*.id +} + +output "appgateway_backend_http_4xx_errors_id" { + description = "id for monitor appgateway_backend_http_4xx_errors" + value = datadog_monitor.appgateway_backend_http_4xx_errors.*.id +} + +output "appgateway_backend_http_5xx_errors_id" { + description = "id for monitor appgateway_backend_http_5xx_errors" + value = datadog_monitor.appgateway_backend_http_5xx_errors.*.id +} + +output "appgateway_failed_requests_id" { + description = "id for monitor appgateway_failed_requests" + value = datadog_monitor.appgateway_failed_requests.*.id +} + +output "appgateway_healthy_host_ratio_id" { + description = "id for monitor appgateway_healthy_host_ratio" + value = datadog_monitor.appgateway_healthy_host_ratio.*.id +} + +output "appgateway_http_4xx_errors_id" { + description = "id for monitor appgateway_http_4xx_errors" + value = datadog_monitor.appgateway_http_4xx_errors.*.id +} + +output "appgateway_http_5xx_errors_id" { + description = "id for monitor appgateway_http_5xx_errors" + value = datadog_monitor.appgateway_http_5xx_errors.*.id +} + +output "appgateway_status_id" { + description = "id for monitor appgateway_status" + value = datadog_monitor.appgateway_status.*.id +} + +output "total_requests_id" { + description = "id for monitor total_requests" + value = datadog_monitor.total_requests.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-gateway/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-gateway/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-gateway/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-services/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-services/README.md new file mode 100755 index 0000000..fbd62be --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-services/README.md @@ -0,0 +1,124 @@ +# CLOUD AZURE APP-SERVICES DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-app-services" { + source = "claranet/monitors/datadog//cloud/azure/app-services" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- App Services HTTP 4xx errors too high +- App Services HTTP 5xx errors too high +- App Services HTTP successful responses too low +- App Services is down +- App Services memory usage +- App Services response time too high + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.appservices_http_4xx_errors_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appservices_http_5xx_errors_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appservices_http_success_status_rate](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appservices_memory_usage_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appservices_response_time](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.appservices_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [appservices\_status\_no\_data\_timeframe](#input\_appservices\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [http\_4xx\_requests\_enabled](#input\_http\_4xx\_requests\_enabled) | Flag to enable App Services 4xx requests monitor | `string` | `"true"` | no | +| [http\_4xx\_requests\_extra\_tags](#input\_http\_4xx\_requests\_extra\_tags) | Extra tags for App Services 4xx requests monitor | `list(string)` | `[]` | no | +| [http\_4xx\_requests\_message](#input\_http\_4xx\_requests\_message) | Custom message for App Services 4xx requests monitor | `string` | `""` | no | +| [http\_4xx\_requests\_threshold\_critical](#input\_http\_4xx\_requests\_threshold\_critical) | Maximum critical acceptable percent of 4xx errors | `number` | `90` | no | +| [http\_4xx\_requests\_threshold\_warning](#input\_http\_4xx\_requests\_threshold\_warning) | Warning regarding acceptable percent of 4xx errors | `number` | `50` | no | +| [http\_4xx\_requests\_time\_aggregator](#input\_http\_4xx\_requests\_time\_aggregator) | Monitor aggregator for App Services 4xx requests [available values: min, max or avg] | `string` | `"min"` | no | +| [http\_4xx\_requests\_timeframe](#input\_http\_4xx\_requests\_timeframe) | Monitor timeframe for App Services 4xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [http\_5xx\_requests\_enabled](#input\_http\_5xx\_requests\_enabled) | Flag to enable App Services 5xx requests monitor | `string` | `"true"` | no | +| [http\_5xx\_requests\_extra\_tags](#input\_http\_5xx\_requests\_extra\_tags) | Extra tags for App Services 5xx requests monitor | `list(string)` | `[]` | no | +| [http\_5xx\_requests\_message](#input\_http\_5xx\_requests\_message) | Custom message for App Services 5xx requests monitor | `string` | `""` | no | +| [http\_5xx\_requests\_threshold\_critical](#input\_http\_5xx\_requests\_threshold\_critical) | Maximum critical acceptable percent of 5xx errors | `number` | `90` | no | +| [http\_5xx\_requests\_threshold\_warning](#input\_http\_5xx\_requests\_threshold\_warning) | Warning regarding acceptable percent of 5xx errors | `number` | `50` | no | +| [http\_5xx\_requests\_time\_aggregator](#input\_http\_5xx\_requests\_time\_aggregator) | Monitor aggregator for App Services 5xx requests [available values: min, max or avg] | `string` | `"min"` | no | +| [http\_5xx\_requests\_timeframe](#input\_http\_5xx\_requests\_timeframe) | Monitor timeframe for App Services 5xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [http\_successful\_requests\_enabled](#input\_http\_successful\_requests\_enabled) | Flag to enable App Services successful requests monitor | `string` | `"true"` | no | +| [http\_successful\_requests\_extra\_tags](#input\_http\_successful\_requests\_extra\_tags) | Extra tags for App Services successful requests monitor | `list(string)` | `[]` | no | +| [http\_successful\_requests\_message](#input\_http\_successful\_requests\_message) | Custom message for App Services successful requests monitor | `string` | `""` | no | +| [http\_successful\_requests\_threshold\_critical](#input\_http\_successful\_requests\_threshold\_critical) | Minimum critical acceptable percent of 2xx & 3xx requests | `number` | `10` | no | +| [http\_successful\_requests\_threshold\_warning](#input\_http\_successful\_requests\_threshold\_warning) | Warning regarding acceptable percent of 2xx & 3xx requests | `number` | `30` | no | +| [http\_successful\_requests\_time\_aggregator](#input\_http\_successful\_requests\_time\_aggregator) | Monitor aggregator for App Services successful requests [available values: min, max or avg] | `string` | `"max"` | no | +| [http\_successful\_requests\_timeframe](#input\_http\_successful\_requests\_timeframe) | Monitor timeframe for App Services successful requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [memory\_usage\_enabled](#input\_memory\_usage\_enabled) | Flag to enable App Services memory usage monitor | `string` | `"true"` | no | +| [memory\_usage\_extra\_tags](#input\_memory\_usage\_extra\_tags) | Extra tags for App Services memory usage monitor | `list(string)` | `[]` | no | +| [memory\_usage\_message](#input\_memory\_usage\_message) | Custom message for App Services memory usage monitor | `string` | `""` | no | +| [memory\_usage\_threshold\_critical](#input\_memory\_usage\_threshold\_critical) | Alerting threshold in Mib | `number` | `1073741824` | no | +| [memory\_usage\_threshold\_warning](#input\_memory\_usage\_threshold\_warning) | Warning threshold in MiB | `number` | `536870912` | no | +| [memory\_usage\_time\_aggregator](#input\_memory\_usage\_time\_aggregator) | Monitor aggregator for App Services memory usage [available values: min, max or avg] | `string` | `"min"` | no | +| [memory\_usage\_timeframe](#input\_memory\_usage\_timeframe) | Monitor timeframe for App Services memory usage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [response\_time\_enabled](#input\_response\_time\_enabled) | Flag to enable App Services response time monitor | `string` | `"true"` | no | +| [response\_time\_extra\_tags](#input\_response\_time\_extra\_tags) | Extra tags for App Services response time monitor | `list(string)` | `[]` | no | +| [response\_time\_message](#input\_response\_time\_message) | Custom message for App Services response time monitor | `string` | `""` | no | +| [response\_time\_threshold\_critical](#input\_response\_time\_threshold\_critical) | Alerting threshold for response time in seconds | `number` | `10` | no | +| [response\_time\_threshold\_warning](#input\_response\_time\_threshold\_warning) | Warning threshold for response time in seconds | `number` | `5` | no | +| [response\_time\_time\_aggregator](#input\_response\_time\_time\_aggregator) | Monitor aggregator for App Services response time [available values: min, max or avg] | `string` | `"min"` | no | +| [response\_time\_timeframe](#input\_response\_time\_timeframe) | Monitor timeframe for App Services response time [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable App Services status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for App Services status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for App Services status monitor | `string` | `""` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for App Services status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for App Services status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [appservices\_http\_4xx\_errors\_count\_id](#output\_appservices\_http\_4xx\_errors\_count\_id) | id for monitor appservices\_http\_4xx\_errors\_count | +| [appservices\_http\_5xx\_errors\_count\_id](#output\_appservices\_http\_5xx\_errors\_count\_id) | id for monitor appservices\_http\_5xx\_errors\_count | +| [appservices\_http\_success\_status\_rate\_id](#output\_appservices\_http\_success\_status\_rate\_id) | id for monitor appservices\_http\_success\_status\_rate | +| [appservices\_memory\_usage\_count\_id](#output\_appservices\_memory\_usage\_count\_id) | id for monitor appservices\_memory\_usage\_count | +| [appservices\_response\_time\_id](#output\_appservices\_response\_time\_id) | id for monitor appservices\_response\_time | +| [appservices\_status\_id](#output\_appservices\_status\_id) | id for monitor appservices\_status | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure_app_services](https://docs.datadoghq.com/integrations/azure_app_services) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-services/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-services/inputs.tf new file mode 100755 index 0000000..a0c9b0e --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-services/inputs.tf @@ -0,0 +1,282 @@ +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "appservices_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# Azure App Services specific variables + +variable "response_time_enabled" { + description = "Flag to enable App Services response time monitor" + type = string + default = "true" +} + +variable "response_time_extra_tags" { + description = "Extra tags for App Services response time monitor" + type = list(string) + default = [] +} + +variable "response_time_message" { + description = "Custom message for App Services response time monitor" + type = string + default = "" +} + +variable "response_time_time_aggregator" { + description = "Monitor aggregator for App Services response time [available values: min, max or avg]" + type = string + default = "min" +} + +variable "response_time_timeframe" { + description = "Monitor timeframe for App Services response time [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "response_time_threshold_critical" { + default = 10 + description = "Alerting threshold for response time in seconds" +} + +variable "response_time_threshold_warning" { + default = 5 + description = "Warning threshold for response time in seconds" +} + +variable "memory_usage_enabled" { + description = "Flag to enable App Services memory usage monitor" + type = string + default = "true" +} + +variable "memory_usage_extra_tags" { + description = "Extra tags for App Services memory usage monitor" + type = list(string) + default = [] +} + +variable "memory_usage_message" { + description = "Custom message for App Services memory usage monitor" + type = string + default = "" +} + +variable "memory_usage_time_aggregator" { + description = "Monitor aggregator for App Services memory usage [available values: min, max or avg]" + type = string + default = "min" +} + +variable "memory_usage_timeframe" { + description = "Monitor timeframe for App Services memory usage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "memory_usage_threshold_critical" { + default = 1073741824 # 1Gb + description = "Alerting threshold in Mib" +} + +variable "memory_usage_threshold_warning" { + default = 536870912 # 512Mb + description = "Warning threshold in MiB" +} + +variable "http_4xx_requests_enabled" { + description = "Flag to enable App Services 4xx requests monitor" + type = string + default = "true" +} + +variable "http_4xx_requests_extra_tags" { + description = "Extra tags for App Services 4xx requests monitor" + type = list(string) + default = [] +} + +variable "http_4xx_requests_message" { + description = "Custom message for App Services 4xx requests monitor" + type = string + default = "" +} + +variable "http_4xx_requests_time_aggregator" { + description = "Monitor aggregator for App Services 4xx requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "http_4xx_requests_timeframe" { + description = "Monitor timeframe for App Services 4xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "http_4xx_requests_threshold_critical" { + default = 90 + description = "Maximum critical acceptable percent of 4xx errors" +} + +variable "http_4xx_requests_threshold_warning" { + default = 50 + description = "Warning regarding acceptable percent of 4xx errors" +} + +variable "http_5xx_requests_enabled" { + description = "Flag to enable App Services 5xx requests monitor" + type = string + default = "true" +} + +variable "http_5xx_requests_extra_tags" { + description = "Extra tags for App Services 5xx requests monitor" + type = list(string) + default = [] +} + +variable "http_5xx_requests_message" { + description = "Custom message for App Services 5xx requests monitor" + type = string + default = "" +} + +variable "http_5xx_requests_time_aggregator" { + description = "Monitor aggregator for App Services 5xx requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "http_5xx_requests_timeframe" { + description = "Monitor timeframe for App Services 5xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "http_5xx_requests_threshold_critical" { + default = 90 + description = "Maximum critical acceptable percent of 5xx errors" +} + +variable "http_5xx_requests_threshold_warning" { + default = 50 + description = "Warning regarding acceptable percent of 5xx errors" +} + +variable "http_successful_requests_enabled" { + description = "Flag to enable App Services successful requests monitor" + type = string + default = "true" +} + +variable "http_successful_requests_extra_tags" { + description = "Extra tags for App Services successful requests monitor" + type = list(string) + default = [] +} + +variable "http_successful_requests_message" { + description = "Custom message for App Services successful requests monitor" + type = string + default = "" +} + +variable "http_successful_requests_time_aggregator" { + description = "Monitor aggregator for App Services successful requests [available values: min, max or avg]" + type = string + default = "max" +} + +variable "http_successful_requests_timeframe" { + description = "Monitor timeframe for App Services successful requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "http_successful_requests_threshold_critical" { + default = 10 + description = "Minimum critical acceptable percent of 2xx & 3xx requests" +} + +variable "http_successful_requests_threshold_warning" { + default = 30 + description = "Warning regarding acceptable percent of 2xx & 3xx requests" +} + +variable "status_enabled" { + description = "Flag to enable App Services status monitor" + type = string + default = "true" +} + +variable "status_message" { + description = "Custom message for App Services status monitor" + type = string + default = "" +} + +variable "status_extra_tags" { + description = "Extra tags for App Services status monitor" + type = list(string) + default = [] +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for App Services status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for App Services status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-services/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-services/modules.tf new file mode 100755 index 0000000..6fe848d --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-services/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_app-services" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-services/monitors-app_services.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-services/monitors-app_services.tf new file mode 100755 index 0000000..319d203 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/app-services/monitors-app_services.tf @@ -0,0 +1,177 @@ +# Monitoring App Services response time +resource "datadog_monitor" "appservices_response_time" { + count = var.response_time_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Services response time too high {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + message = coalesce(var.response_time_message, var.message) + type = "query alert" + + query = < ${var.response_time_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.response_time_threshold_warning + critical = var.response_time_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:app-services", "team:claranet", "created-by:terraform"], var.response_time_extra_tags) +} + +# Monitoring App Services memory usage +resource "datadog_monitor" "appservices_memory_usage_count" { + count = var.memory_usage_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Services memory usage {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.memory_usage_message, var.message) + type = "query alert" + + query = < ${var.memory_usage_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.memory_usage_threshold_warning + critical = var.memory_usage_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:app-services", "team:claranet", "created-by:terraform"], var.memory_usage_extra_tags) +} + +# Monitoring App Services 5xx errors percent +resource "datadog_monitor" "appservices_http_5xx_errors_count" { + count = var.http_5xx_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Services HTTP 5xx errors too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.http_5xx_requests_message, var.message) + type = "query alert" + + query = < ${var.http_5xx_requests_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.http_5xx_requests_threshold_warning + critical = var.http_5xx_requests_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 1 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:app-services", "team:claranet", "created-by:terraform"], var.http_5xx_requests_extra_tags) +} + +# Monitoring App Services 4xx errors percent +resource "datadog_monitor" "appservices_http_4xx_errors_count" { + count = var.http_4xx_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Services HTTP 4xx errors too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.http_4xx_requests_message, var.message) + type = "query alert" + + query = < ${var.http_4xx_requests_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.http_4xx_requests_threshold_warning + critical = var.http_4xx_requests_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false # Will NOT notify when no data is received + renotify_interval = 0 + require_full_window = false + timeout_h = 1 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:app-services", "team:claranet", "created-by:terraform"], var.http_4xx_requests_extra_tags) +} + +# Monitoring App Services HTTP 2xx & 3xx status pages percent +resource "datadog_monitor" "appservices_http_success_status_rate" { + count = var.http_successful_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] App Services HTTP successful responses too low {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + type = "query alert" + message = coalesce(var.http_successful_requests_message, var.message) + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.azure_search_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.azure_search_throttled_queries_rate](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [azure\_search\_latency\_no\_data\_timeframe](#input\_azure\_search\_latency\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [latency\_enabled](#input\_latency\_enabled) | Flag to enable Azure Search latency monitor | `string` | `"true"` | no | +| [latency\_extra\_tags](#input\_latency\_extra\_tags) | Extra tags for Azure Search latency monitor | `list(string)` | `[]` | no | +| [latency\_message](#input\_latency\_message) | Custom message for Azure Search latency monitor | `string` | `""` | no | +| [latency\_threshold\_critical](#input\_latency\_threshold\_critical) | Alerting threshold for Azure Search latency in seconds | `number` | `4` | no | +| [latency\_threshold\_warning](#input\_latency\_threshold\_warning) | Warning threshold for Azure Search latency in seconds | `number` | `2` | no | +| [latency\_time\_aggregator](#input\_latency\_time\_aggregator) | Monitor aggregator for Azure Search latency [available values: min, max or avg] | `string` | `"min"` | no | +| [latency\_timeframe](#input\_latency\_timeframe) | Monitor timeframe for Azure Search latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [throttled\_queries\_rate\_enabled](#input\_throttled\_queries\_rate\_enabled) | Flag to enable Azure Search throttled queries rate monitor | `string` | `"true"` | no | +| [throttled\_queries\_rate\_extra\_tags](#input\_throttled\_queries\_rate\_extra\_tags) | Extra tags for Azure Search throttled queries rate monitor | `list(string)` | `[]` | no | +| [throttled\_queries\_rate\_message](#input\_throttled\_queries\_rate\_message) | Custom message for Azure Search throttled queries rate monitor | `string` | `""` | no | +| [throttled\_queries\_rate\_threshold\_critical](#input\_throttled\_queries\_rate\_threshold\_critical) | Alerting threshold for Azure Search throttled queries rate | `number` | `50` | no | +| [throttled\_queries\_rate\_threshold\_warning](#input\_throttled\_queries\_rate\_threshold\_warning) | Warning threshold for Azure Search throttled queries rate | `number` | `25` | no | +| [throttled\_queries\_rate\_time\_aggregator](#input\_throttled\_queries\_rate\_time\_aggregator) | Monitor aggregator for Azure Search throttled queries rate [available values: min, max or avg] | `string` | `"min"` | no | +| [throttled\_queries\_rate\_timeframe](#input\_throttled\_queries\_rate\_timeframe) | Monitor timeframe for Azure Search throttled queries rate [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [azure\_search\_latency\_id](#output\_azure\_search\_latency\_id) | id for monitor azure\_search\_latency | +| [azure\_search\_throttled\_queries\_rate\_id](#output\_azure\_search\_throttled\_queries\_rate\_id) | id for monitor azure\_search\_throttled\_queries\_rate | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure_app_services](https://docs.datadoghq.com/integrations/azure_app_services) + +Azure Documentation [https://docs.microsoft.com/en-us/azure/search/search-monitor-usage](https://docs.microsoft.com/en-us/azure/search/search-monitor-usage) + +Azure monitor metrics [https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-supported#microsoftsearchsearchservices](https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-supported#microsoftsearchsearchservices) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/azure-search/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/azure-search/inputs.tf new file mode 100755 index 0000000..ca0b277 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/azure-search/inputs.tf @@ -0,0 +1,132 @@ +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "azure_search_latency_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# Azure Search specific variables + +variable "latency_enabled" { + description = "Flag to enable Azure Search latency monitor" + type = string + default = "true" +} + +variable "latency_extra_tags" { + description = "Extra tags for Azure Search latency monitor" + type = list(string) + default = [] +} + +variable "latency_message" { + description = "Custom message for Azure Search latency monitor" + type = string + default = "" +} + +variable "latency_time_aggregator" { + description = "Monitor aggregator for Azure Search latency [available values: min, max or avg]" + type = string + default = "min" +} + +variable "latency_timeframe" { + description = "Monitor timeframe for Azure Search latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "latency_threshold_critical" { + default = 4 + description = "Alerting threshold for Azure Search latency in seconds" +} + +variable "latency_threshold_warning" { + default = 2 + description = "Warning threshold for Azure Search latency in seconds" +} + +variable "throttled_queries_rate_enabled" { + description = "Flag to enable Azure Search throttled queries rate monitor" + type = string + default = "true" +} + +variable "throttled_queries_rate_extra_tags" { + description = "Extra tags for Azure Search throttled queries rate monitor" + type = list(string) + default = [] +} + +variable "throttled_queries_rate_message" { + description = "Custom message for Azure Search throttled queries rate monitor" + type = string + default = "" +} + +variable "throttled_queries_rate_time_aggregator" { + description = "Monitor aggregator for Azure Search throttled queries rate [available values: min, max or avg]" + type = string + default = "min" +} + +variable "throttled_queries_rate_timeframe" { + description = "Monitor timeframe for Azure Search throttled queries rate [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "throttled_queries_rate_threshold_critical" { + default = 50 + description = "Alerting threshold for Azure Search throttled queries rate" +} + +variable "throttled_queries_rate_threshold_warning" { + default = 25 + description = "Warning threshold for Azure Search throttled queries rate" +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/azure-search/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/azure-search/modules.tf new file mode 100755 index 0000000..27f1095 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/azure-search/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_search" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/azure-search/monitors-azure-search.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/azure-search/monitors-azure-search.tf new file mode 100755 index 0000000..5788f48 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/azure-search/monitors-azure-search.tf @@ -0,0 +1,59 @@ +# Monitoring Azure Search latency +resource "datadog_monitor" "azure_search_latency" { + count = var.latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Search latency too high {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + message = coalesce(var.latency_message, var.message) + type = "query alert" + + query = < ${var.latency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.latency_threshold_warning + critical = var.latency_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = var.notify_no_data + no_data_timeframe = var.azure_search_latency_no_data_timeframe + renotify_interval = 0 + require_full_window = false + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:azure-search", "team:claranet", "created-by:terraform"], var.latency_extra_tags) +} + +# Monitoring Azure Search throttled queries +resource "datadog_monitor" "azure_search_throttled_queries_rate" { + count = var.throttled_queries_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Search throttled queries rate is too high {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + message = coalesce(var.throttled_queries_rate_message, var.message) + type = "query alert" + + query = < ${var.throttled_queries_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.throttled_queries_rate_threshold_warning + critical = var.throttled_queries_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:azure-search", "team:claranet", "created-by:terraform"], var.throttled_queries_rate_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/azure-search/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/azure-search/outputs.tf new file mode 100755 index 0000000..c4e9e54 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/azure-search/outputs.tf @@ -0,0 +1,10 @@ +output "azure_search_latency_id" { + description = "id for monitor azure_search_latency" + value = datadog_monitor.azure_search_latency.*.id +} + +output "azure_search_throttled_queries_rate_id" { + description = "id for monitor azure_search_throttled_queries_rate" + value = datadog_monitor.azure_search_throttled_queries_rate.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/azure-search/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/azure-search/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/azure-search/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/cosmosdb/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/cosmosdb/README.md new file mode 100755 index 0000000..3db2e4b --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/cosmosdb/README.md @@ -0,0 +1,110 @@ +# CLOUD AZURE COSMOSDB DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-cosmosdb" { + source = "claranet/monitors/datadog//cloud/azure/cosmosdb" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Cosmos DB 4xx requests rate is high +- Cosmos DB 5xx requests rate is high +- Cosmos DB is down +- Cosmos DB max scaling reached for collection + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | +| [filter-tags-statuscode](#module\_filter-tags-statuscode) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cosmos_db_4xx_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.cosmos_db_5xx_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.cosmos_db_scaling](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.cosmos_db_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cosmos\_db\_4xx\_request\_extra\_tags](#input\_cosmos\_db\_4xx\_request\_extra\_tags) | Extra tags for Cosmos DB 4xx requests monitor | `list(string)` | `[]` | no | +| [cosmos\_db\_4xx\_request\_rate\_threshold\_critical](#input\_cosmos\_db\_4xx\_request\_rate\_threshold\_critical) | Critical threshold for Cosmos DB 4xx requests monitor | `number` | `80` | no | +| [cosmos\_db\_4xx\_request\_rate\_threshold\_warning](#input\_cosmos\_db\_4xx\_request\_rate\_threshold\_warning) | Warning threshold for Cosmos DB 4xx requests monitor | `number` | `50` | no | +| [cosmos\_db\_4xx\_request\_time\_aggregator](#input\_cosmos\_db\_4xx\_request\_time\_aggregator) | Monitor aggregator for Cosmos DB 4xx requests [available values: min, max or avg] | `string` | `"min"` | no | +| [cosmos\_db\_4xx\_request\_timeframe](#input\_cosmos\_db\_4xx\_request\_timeframe) | Monitor timeframe for Cosmos DB 4xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [cosmos\_db\_4xx\_requests\_enabled](#input\_cosmos\_db\_4xx\_requests\_enabled) | Flag to enable Cosmos DB 4xx requests monitor | `string` | `"true"` | no | +| [cosmos\_db\_4xx\_requests\_message](#input\_cosmos\_db\_4xx\_requests\_message) | Custom message for Cosmos DB 4xx requests monitor | `string` | `""` | no | +| [cosmos\_db\_5xx\_request\_rate\_extra\_tags](#input\_cosmos\_db\_5xx\_request\_rate\_extra\_tags) | Extra tags for Cosmos DB 5xx requests monitor | `list(string)` | `[]` | no | +| [cosmos\_db\_5xx\_request\_rate\_threshold\_critical](#input\_cosmos\_db\_5xx\_request\_rate\_threshold\_critical) | Critical threshold for Cosmos DB 5xx requests monitor | `number` | `80` | no | +| [cosmos\_db\_5xx\_request\_rate\_threshold\_warning](#input\_cosmos\_db\_5xx\_request\_rate\_threshold\_warning) | Warning threshold for Cosmos DB 5xx requests monitor | `number` | `50` | no | +| [cosmos\_db\_5xx\_request\_time\_aggregator](#input\_cosmos\_db\_5xx\_request\_time\_aggregator) | Monitor aggregator for Cosmos DB 5xx requests [available values: min, max or avg] | `string` | `"min"` | no | +| [cosmos\_db\_5xx\_request\_timeframe](#input\_cosmos\_db\_5xx\_request\_timeframe) | Monitor timeframe for Cosmos DB 5xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [cosmos\_db\_5xx\_requests\_enabled](#input\_cosmos\_db\_5xx\_requests\_enabled) | Flag to enable Cosmos DB 5xx requests monitor | `string` | `"true"` | no | +| [cosmos\_db\_5xx\_requests\_message](#input\_cosmos\_db\_5xx\_requests\_message) | Custom message for Cosmos DB 5xx requests monitor | `string` | `""` | no | +| [cosmos\_db\_scaling\_enabled](#input\_cosmos\_db\_scaling\_enabled) | Flag to enable Cosmos DB scaling monitor | `string` | `"true"` | no | +| [cosmos\_db\_scaling\_error\_rate\_threshold\_critical](#input\_cosmos\_db\_scaling\_error\_rate\_threshold\_critical) | Critical threshold for Cosmos DB scaling monitor | `number` | `10` | no | +| [cosmos\_db\_scaling\_error\_rate\_threshold\_warning](#input\_cosmos\_db\_scaling\_error\_rate\_threshold\_warning) | Warning threshold for Cosmos DB scaling monitor | `number` | `5` | no | +| [cosmos\_db\_scaling\_extra\_tags](#input\_cosmos\_db\_scaling\_extra\_tags) | Extra tags for Cosmos DB scaling monitor | `list(string)` | `[]` | no | +| [cosmos\_db\_scaling\_message](#input\_cosmos\_db\_scaling\_message) | Custom message for Cosmos DB scaling monitor | `string` | `""` | no | +| [cosmos\_db\_scaling\_time\_aggregator](#input\_cosmos\_db\_scaling\_time\_aggregator) | Monitor aggregator for Cosmos DB scaling [available values: min, max or avg] | `string` | `"min"` | no | +| [cosmos\_db\_scaling\_timeframe](#input\_cosmos\_db\_scaling\_timeframe) | Monitor timeframe for Cosmos DB scaling [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [cosmos\_db\_status\_no\_data\_timeframe](#input\_cosmos\_db\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable Cosmos DB status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for Cosmos DB status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for Cosmos DB status monitor | `string` | `""` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for Cosmos DB status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for Cosmos DB status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cosmos\_db\_4xx\_requests\_id](#output\_cosmos\_db\_4xx\_requests\_id) | id for monitor cosmos\_db\_4xx\_requests | +| [cosmos\_db\_5xx\_requests\_id](#output\_cosmos\_db\_5xx\_requests\_id) | id for monitor cosmos\_db\_5xx\_requests | +| [cosmos\_db\_scaling\_id](#output\_cosmos\_db\_scaling\_id) | id for monitor cosmos\_db\_scaling | +| [cosmos\_db\_status\_id](#output\_cosmos\_db\_status\_id) | id for monitor cosmos\_db\_status | +## Related documentation + +DataDog documentation : [https://docs.datadoghq.com/integrations/azure/](https://docs.datadoghq.com/integrations/azure/) +You must search `cosmosdb`, there is no integration for now. + +Azure metrics documentation : [https://docs.microsoft.com/fr-fr/azure/monitoring-and-diagnostics/monitoring-supported-metrics#microsoftdocumentdbdatabaseaccounts](https://docs.microsoft.com/fr-fr/azure/monitoring-and-diagnostics/monitoring-supported-metrics#microsoftdocumentdbdatabaseaccounts) + +429 status code : [https://docs.microsoft.com/en-us/rest/api/cosmos-db/http-status-codes-for-cosmosdb](https://docs.microsoft.com/en-us/rest/api/cosmos-db/http-status-codes-for-cosmosdb) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/cosmosdb/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/cosmosdb/inputs.tf new file mode 100755 index 0000000..585a764 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/cosmosdb/inputs.tf @@ -0,0 +1,201 @@ +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "cosmos_db_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# Azure CosmosDB specific variables +variable "status_enabled" { + description = "Flag to enable Cosmos DB status monitor" + type = string + default = "true" +} + +variable "status_extra_tags" { + description = "Extra tags for Cosmos DB status monitor" + type = list(string) + default = [] +} + +variable "status_message" { + description = "Custom message for Cosmos DB status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for Cosmos DB status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for Cosmos DB status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "cosmos_db_4xx_requests_message" { + description = "Custom message for Cosmos DB 4xx requests monitor" + type = string + default = "" +} + +variable "cosmos_db_4xx_requests_enabled" { + description = "Flag to enable Cosmos DB 4xx requests monitor" + type = string + default = "true" +} + +variable "cosmos_db_4xx_request_rate_threshold_critical" { + description = "Critical threshold for Cosmos DB 4xx requests monitor" + default = 80 +} + +variable "cosmos_db_4xx_request_rate_threshold_warning" { + description = "Warning threshold for Cosmos DB 4xx requests monitor" + default = 50 +} + +variable "cosmos_db_4xx_request_extra_tags" { + description = "Extra tags for Cosmos DB 4xx requests monitor" + type = list(string) + default = [] +} + +variable "cosmos_db_4xx_request_time_aggregator" { + description = "Monitor aggregator for Cosmos DB 4xx requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cosmos_db_4xx_request_timeframe" { + description = "Monitor timeframe for Cosmos DB 4xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "cosmos_db_5xx_requests_message" { + description = "Custom message for Cosmos DB 5xx requests monitor" + type = string + default = "" +} + +variable "cosmos_db_5xx_requests_enabled" { + description = "Flag to enable Cosmos DB 5xx requests monitor" + type = string + default = "true" +} + +variable "cosmos_db_5xx_request_rate_threshold_critical" { + description = "Critical threshold for Cosmos DB 5xx requests monitor" + default = 80 +} + +variable "cosmos_db_5xx_request_rate_threshold_warning" { + description = "Warning threshold for Cosmos DB 5xx requests monitor" + default = 50 +} + +variable "cosmos_db_5xx_request_rate_extra_tags" { + description = "Extra tags for Cosmos DB 5xx requests monitor" + type = list(string) + default = [] +} + +variable "cosmos_db_5xx_request_time_aggregator" { + description = "Monitor aggregator for Cosmos DB 5xx requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cosmos_db_5xx_request_timeframe" { + description = "Monitor timeframe for Cosmos DB 5xx requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "cosmos_db_scaling_message" { + description = "Custom message for Cosmos DB scaling monitor" + type = string + default = "" +} + +variable "cosmos_db_scaling_enabled" { + description = "Flag to enable Cosmos DB scaling monitor" + type = string + default = "true" +} + +variable "cosmos_db_scaling_error_rate_threshold_critical" { + description = "Critical threshold for Cosmos DB scaling monitor" + default = 10 +} + +variable "cosmos_db_scaling_error_rate_threshold_warning" { + description = "Warning threshold for Cosmos DB scaling monitor" + default = 5 +} + +variable "cosmos_db_scaling_extra_tags" { + description = "Extra tags for Cosmos DB scaling monitor" + type = list(string) + default = [] +} + +variable "cosmos_db_scaling_time_aggregator" { + description = "Monitor aggregator for Cosmos DB scaling [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cosmos_db_scaling_timeframe" { + description = "Monitor timeframe for Cosmos DB scaling [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/cosmosdb/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/cosmosdb/modules.tf new file mode 100755 index 0000000..d54aaf2 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/cosmosdb/modules.tf @@ -0,0 +1,21 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_cosmosdb" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + +module "filter-tags-statuscode" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_cosmosdb" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["statuscode:%s"] +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/cosmosdb/monitors-cosmosdb.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/cosmosdb/monitors-cosmosdb.tf new file mode 100755 index 0000000..fee4748 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/cosmosdb/monitors-cosmosdb.tf @@ -0,0 +1,135 @@ +resource "datadog_monitor" "cosmos_db_status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Cosmos DB is down" + message = coalesce(var.status_message, var.message) + type = "metric alert" + + query = < ${var.cosmos_db_4xx_request_rate_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.cosmos_db_4xx_request_rate_threshold_critical + warning = var.cosmos_db_4xx_request_rate_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:cosmos_db", "team:claranet", "created-by:terraform"], var.cosmos_db_4xx_request_extra_tags) +} + +resource "datadog_monitor" "cosmos_db_5xx_requests" { + count = var.cosmos_db_5xx_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Cosmos DB 5xx requests rate is high {{#is_alert}}{{comparator}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{comparator}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cosmos_db_5xx_requests_message, var.message) + type = "query alert" + + query = < ${var.cosmos_db_5xx_request_rate_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.cosmos_db_5xx_request_rate_threshold_critical + warning = var.cosmos_db_5xx_request_rate_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:cosmos_db", "team:claranet", "created-by:terraform"], var.cosmos_db_5xx_request_rate_extra_tags) +} + +resource "datadog_monitor" "cosmos_db_scaling" { + count = var.cosmos_db_scaling_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Cosmos DB max scaling reached for collection {{#is_alert}}{{comparator}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{comparator}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cosmos_db_scaling_message, var.message) + type = "query alert" + + # List of available status codes : https://docs.microsoft.com/en-us/rest/api/cosmos-db/http-status-codes-for-cosmosdb + query = < ${var.cosmos_db_scaling_error_rate_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.cosmos_db_scaling_error_rate_threshold_critical + warning = var.cosmos_db_scaling_error_rate_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:cosmos_db", "team:claranet", "created-by:terraform"], var.cosmos_db_scaling_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/cosmosdb/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/cosmosdb/outputs.tf new file mode 100755 index 0000000..7958283 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/cosmosdb/outputs.tf @@ -0,0 +1,20 @@ +output "cosmos_db_4xx_requests_id" { + description = "id for monitor cosmos_db_4xx_requests" + value = datadog_monitor.cosmos_db_4xx_requests.*.id +} + +output "cosmos_db_5xx_requests_id" { + description = "id for monitor cosmos_db_5xx_requests" + value = datadog_monitor.cosmos_db_5xx_requests.*.id +} + +output "cosmos_db_scaling_id" { + description = "id for monitor cosmos_db_scaling" + value = datadog_monitor.cosmos_db_scaling.*.id +} + +output "cosmos_db_status_id" { + description = "id for monitor cosmos_db_status" + value = datadog_monitor.cosmos_db_status.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/cosmosdb/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/cosmosdb/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/cosmosdb/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/datalakestore/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/datalakestore/README.md new file mode 100755 index 0000000..180af1a --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/datalakestore/README.md @@ -0,0 +1,77 @@ +# CLOUD AZURE DATALAKESTORE DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-datalakestore" { + source = "claranet/monitors/datadog//cloud/azure/datalakestore" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Datalake Store is down + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.datalakestore_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [datalakestore\_status\_no\_data\_timeframe](#input\_datalakestore\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable Datalake Store status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for Datalake Store status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for Datalake Store status monitor | `string` | `""` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for Datalake Store status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for Datalake Store status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [datalakestore\_status\_id](#output\_datalakestore\_status\_id) | id for monitor datalakestore\_status | +## Related documentation + +DataDog documentation : [https://docs.datadoghq.com/integrations/azure/](https://docs.datadoghq.com/integrations/azure/) +You must search `datalake`, there is no integration for now. + +Azure metrics documentation : [https://docs.microsoft.com/fr-fr/azure/monitoring-and-diagnostics/monitoring-supported-metrics#microsoftdatalakestoreaccounts](https://docs.microsoft.com/fr-fr/azure/monitoring-and-diagnostics/monitoring-supported-metrics#microsoftdatalakestoreaccounts) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/datalakestore/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/datalakestore/inputs.tf new file mode 100755 index 0000000..ba4e314 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/datalakestore/inputs.tf @@ -0,0 +1,80 @@ +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "datalakestore_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# Azure Datalake Store specific variables +variable "status_enabled" { + description = "Flag to enable Datalake Store status monitor" + type = string + default = "true" +} + +variable "status_message" { + description = "Custom message for Datalake Store status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for Datalake Store status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for Datalake Store status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + default = "last_5m" +} + +variable "status_extra_tags" { + description = "Extra tags for Datalake Store status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/datalakestore/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/datalakestore/modules.tf new file mode 100755 index 0000000..b837d67 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/datalakestore/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_datalakestore" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/datalakestore/monitors-datalakestore.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/datalakestore/monitors-datalakestore.tf new file mode 100755 index 0000000..0d8fa42 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/datalakestore/monitors-datalakestore.tf @@ -0,0 +1,26 @@ +resource "datadog_monitor" "datalakestore_status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Datalake Store is down" + message = coalesce(var.status_message, var.message) + type = "query alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.eventgrid_failed_messages](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.eventgrid_no_successful_message](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.eventgrid_unmatched_events](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [eventgrid\_no\_successful\_message\_no\_data\_timeframe](#input\_eventgrid\_no\_successful\_message\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [failed\_messages\_rate\_enabled](#input\_failed\_messages\_rate\_enabled) | Flag to enable Event Grid failed messages monitor | `string` | `"true"` | no | +| [failed\_messages\_rate\_extra\_tags](#input\_failed\_messages\_rate\_extra\_tags) | Extra tags for Event Grid failed messages monitor | `list(string)` | `[]` | no | +| [failed\_messages\_rate\_message](#input\_failed\_messages\_rate\_message) | Custom message for Event Grid failed messages monitor | `string` | `""` | no | +| [failed\_messages\_rate\_thresold\_critical](#input\_failed\_messages\_rate\_thresold\_critical) | Failed messages ratio (percentage) to trigger the critical alert | `number` | `90` | no | +| [failed\_messages\_rate\_thresold\_warning](#input\_failed\_messages\_rate\_thresold\_warning) | Failed messages ratio (percentage) to trigger a warning alert | `number` | `50` | no | +| [failed\_messages\_rate\_time\_aggregator](#input\_failed\_messages\_rate\_time\_aggregator) | Monitor aggregator for Event Grid failed messages [available values: min, max or avg] | `string` | `"min"` | no | +| [failed\_messages\_rate\_timeframe](#input\_failed\_messages\_rate\_timeframe) | Monitor timeframe for Event Grid failed messages [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [no\_successful\_message\_rate\_enabled](#input\_no\_successful\_message\_rate\_enabled) | Flag to enable Event Grid no successful message monitor | `string` | `"true"` | no | +| [no\_successful\_message\_rate\_extra\_tags](#input\_no\_successful\_message\_rate\_extra\_tags) | Extra tags for Event Grid no successful message monitor | `list(string)` | `[]` | no | +| [no\_successful\_message\_rate\_message](#input\_no\_successful\_message\_rate\_message) | Custom message for Event Grid no successful message monitor | `string` | `""` | no | +| [no\_successful\_message\_rate\_time\_aggregator](#input\_no\_successful\_message\_rate\_time\_aggregator) | Monitor aggregator for Event Grid no successful message [available values: min, max or avg] | `string` | `"min"` | no | +| [no\_successful\_message\_rate\_timeframe](#input\_no\_successful\_message\_rate\_timeframe) | Monitor timeframe for Event Grid no successful message [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [unmatched\_events\_rate\_enabled](#input\_unmatched\_events\_rate\_enabled) | Flag to enable Event Grid unmatched events monitor | `string` | `"true"` | no | +| [unmatched\_events\_rate\_extra\_tags](#input\_unmatched\_events\_rate\_extra\_tags) | Extra tags for Event Grid unmatched events monitor | `list(string)` | `[]` | no | +| [unmatched\_events\_rate\_message](#input\_unmatched\_events\_rate\_message) | Custom message for Event Grid unmatched events monitor | `string` | `""` | no | +| [unmatched\_events\_rate\_thresold\_critical](#input\_unmatched\_events\_rate\_thresold\_critical) | Unmatched events ratio (percentage) to trigger the critical alert | `number` | `90` | no | +| [unmatched\_events\_rate\_thresold\_warning](#input\_unmatched\_events\_rate\_thresold\_warning) | Unmatched events ratio (percentage) to trigger a warning alert | `number` | `50` | no | +| [unmatched\_events\_rate\_time\_aggregator](#input\_unmatched\_events\_rate\_time\_aggregator) | Monitor aggregator for Event Grid unmatched events [available values: min, max or avg] | `string` | `"min"` | no | +| [unmatched\_events\_rate\_timeframe](#input\_unmatched\_events\_rate\_timeframe) | Monitor timeframe for Event Grid unmatched events [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [eventgrid\_failed\_messages\_id](#output\_eventgrid\_failed\_messages\_id) | id for monitor eventgrid\_failed\_messages | +| [eventgrid\_no\_successful\_message\_id](#output\_eventgrid\_no\_successful\_message\_id) | id for monitor eventgrid\_no\_successful\_message | +| [eventgrid\_unmatched\_events\_id](#output\_eventgrid\_unmatched\_events\_id) | id for monitor eventgrid\_unmatched\_events | +## Related documentation + +Datadog Azure documentation: [https://docs.datadoghq.com/integrations/azure/](https://docs.datadoghq.com/integrations/azure/) + +Azure "Monitor event delivery" documentation: [https://docs.microsoft.com/en-us/azure/event-grid/monitor-event-delivery](https://docs.microsoft.com/en-us/azure/event-grid/monitor-event-delivery) + +Azure Monitor metrics: [https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-supported#microsofteventgridtopics](https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-supported#microsofteventgridtopics) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventgrid/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventgrid/inputs.tf new file mode 100755 index 0000000..61c7693 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventgrid/inputs.tf @@ -0,0 +1,164 @@ +# Global Terraform +variable "environment" { + description = "Architecture environment" + type = string +} + +# Global DataDog +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "eventgrid_no_successful_message_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Azure Event Grid specific variables + +variable "no_successful_message_rate_enabled" { + description = "Flag to enable Event Grid no successful message monitor" + type = string + default = "true" +} + +variable "no_successful_message_rate_extra_tags" { + description = "Extra tags for Event Grid no successful message monitor" + type = list(string) + default = [] +} + +variable "no_successful_message_rate_message" { + description = "Custom message for Event Grid no successful message monitor" + type = string + default = "" +} + +variable "no_successful_message_rate_time_aggregator" { + description = "Monitor aggregator for Event Grid no successful message [available values: min, max or avg]" + type = string + default = "min" +} + +variable "no_successful_message_rate_timeframe" { + description = "Monitor timeframe for Event Grid no successful message [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_messages_rate_enabled" { + description = "Flag to enable Event Grid failed messages monitor" + type = string + default = "true" +} + +variable "failed_messages_rate_extra_tags" { + description = "Extra tags for Event Grid failed messages monitor" + type = list(string) + default = [] +} + +variable "failed_messages_rate_message" { + description = "Custom message for Event Grid failed messages monitor" + type = string + default = "" +} + +variable "failed_messages_rate_time_aggregator" { + description = "Monitor aggregator for Event Grid failed messages [available values: min, max or avg]" + type = string + default = "min" +} + +variable "failed_messages_rate_timeframe" { + description = "Monitor timeframe for Event Grid failed messages [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_messages_rate_thresold_critical" { + description = "Failed messages ratio (percentage) to trigger the critical alert" + default = 90 +} + +variable "failed_messages_rate_thresold_warning" { + description = "Failed messages ratio (percentage) to trigger a warning alert" + default = 50 +} + +variable "unmatched_events_rate_enabled" { + description = "Flag to enable Event Grid unmatched events monitor" + type = string + default = "true" +} + +variable "unmatched_events_rate_extra_tags" { + description = "Extra tags for Event Grid unmatched events monitor" + type = list(string) + default = [] +} + +variable "unmatched_events_rate_message" { + description = "Custom message for Event Grid unmatched events monitor" + type = string + default = "" +} + +variable "unmatched_events_rate_time_aggregator" { + description = "Monitor aggregator for Event Grid unmatched events [available values: min, max or avg]" + type = string + default = "min" +} + +variable "unmatched_events_rate_timeframe" { + description = "Monitor timeframe for Event Grid unmatched events [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "unmatched_events_rate_thresold_critical" { + description = "Unmatched events ratio (percentage) to trigger the critical alert" + default = 90 +} + +variable "unmatched_events_rate_thresold_warning" { + description = "Unmatched events ratio (percentage) to trigger a warning alert" + default = 50 +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventgrid/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventgrid/modules.tf new file mode 100755 index 0000000..2127f87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventgrid/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "eventgrid" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventgrid/monitors-eventgrid.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventgrid/monitors-eventgrid.tf new file mode 100755 index 0000000..efe5402 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventgrid/monitors-eventgrid.tf @@ -0,0 +1,94 @@ +resource "datadog_monitor" "eventgrid_no_successful_message" { + count = var.no_successful_message_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Event Grid no successful message {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.no_successful_message_rate_message, var.message) + type = "metric alert" + + # Query is a bit weird, but we only want to check the no-data + query = < ${var.failed_messages_rate_thresold_critical} +EOQ + + monitor_thresholds { + critical = var.failed_messages_rate_thresold_critical + warning = var.failed_messages_rate_thresold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:eventgrid", "team:claranet", "created-by:terraform"], var.failed_messages_rate_extra_tags) +} + +resource "datadog_monitor" "eventgrid_unmatched_events" { + count = var.unmatched_events_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Event Grid too many unmatched events {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.unmatched_events_rate_message, var.message) + type = "query alert" + + query = < ${var.unmatched_events_rate_thresold_critical} +EOQ + + monitor_thresholds { + critical = var.unmatched_events_rate_thresold_critical + warning = var.unmatched_events_rate_thresold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:eventgrid", "team:claranet", "created-by:terraform"], var.unmatched_events_rate_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventgrid/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventgrid/outputs.tf new file mode 100755 index 0000000..7c58008 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventgrid/outputs.tf @@ -0,0 +1,15 @@ +output "eventgrid_failed_messages_id" { + description = "id for monitor eventgrid_failed_messages" + value = datadog_monitor.eventgrid_failed_messages.*.id +} + +output "eventgrid_no_successful_message_id" { + description = "id for monitor eventgrid_no_successful_message" + value = datadog_monitor.eventgrid_no_successful_message.*.id +} + +output "eventgrid_unmatched_events_id" { + description = "id for monitor eventgrid_unmatched_events" + value = datadog_monitor.eventgrid_unmatched_events.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventgrid/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventgrid/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventgrid/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventhub/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventhub/README.md new file mode 100755 index 0000000..264e0d3 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventhub/README.md @@ -0,0 +1,96 @@ +# CLOUD AZURE EVENTHUB DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-eventhub" { + source = "claranet/monitors/datadog//cloud/azure/eventhub" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Event Hub is down +- Event Hub too many errors +- Event Hub too many failed requests + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.eventhub_errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.eventhub_failed_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.eventhub_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [errors\_rate\_enabled](#input\_errors\_rate\_enabled) | Flag to enable Event Hub errors monitor | `string` | `"true"` | no | +| [errors\_rate\_extra\_tags](#input\_errors\_rate\_extra\_tags) | Extra tags for Event Hub errors monitor | `list(string)` | `[]` | no | +| [errors\_rate\_message](#input\_errors\_rate\_message) | Custom message for Event Hub errors monitor | `string` | `""` | no | +| [errors\_rate\_thresold\_critical](#input\_errors\_rate\_thresold\_critical) | Errors ratio (percentage) to trigger the critical alert | `number` | `90` | no | +| [errors\_rate\_thresold\_warning](#input\_errors\_rate\_thresold\_warning) | Errors ratio (percentage) to trigger a warning alert | `number` | `50` | no | +| [errors\_rate\_time\_aggregator](#input\_errors\_rate\_time\_aggregator) | Monitor aggregator for Event Hub errors [available values: min, max or avg] | `string` | `"min"` | no | +| [errors\_rate\_timeframe](#input\_errors\_rate\_timeframe) | Monitor timeframe for Event Hub errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [eventhub\_status\_no\_data\_timeframe](#input\_eventhub\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [failed\_requests\_rate\_enabled](#input\_failed\_requests\_rate\_enabled) | Flag to enable Event Hub failed requests monitor | `string` | `"true"` | no | +| [failed\_requests\_rate\_extra\_tags](#input\_failed\_requests\_rate\_extra\_tags) | Extra tags for Event Hub failed requests monitor | `list(string)` | `[]` | no | +| [failed\_requests\_rate\_message](#input\_failed\_requests\_rate\_message) | Custom message for Event Hub failed requests monitor | `string` | `""` | no | +| [failed\_requests\_rate\_thresold\_critical](#input\_failed\_requests\_rate\_thresold\_critical) | Failed requests ratio (percentage) to trigger the critical alert | `number` | `90` | no | +| [failed\_requests\_rate\_thresold\_warning](#input\_failed\_requests\_rate\_thresold\_warning) | Failed requests ratio (percentage) to trigger a warning alert | `number` | `50` | no | +| [failed\_requests\_rate\_time\_aggregator](#input\_failed\_requests\_rate\_time\_aggregator) | Monitor aggregator for Event Hub failed requests [available values: min, max or avg] | `string` | `"min"` | no | +| [failed\_requests\_rate\_timeframe](#input\_failed\_requests\_rate\_timeframe) | Monitor timeframe for Event Hub failed requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable Event Hub status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for Event Hub status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for Event Hub status monitor | `string` | `""` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for Event Hub status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for Event Hub status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [eventhub\_errors\_id](#output\_eventhub\_errors\_id) | id for monitor eventhub\_errors | +| [eventhub\_failed\_requests\_id](#output\_eventhub\_failed\_requests\_id) | id for monitor eventhub\_failed\_requests | +| [eventhub\_status\_id](#output\_eventhub\_status\_id) | id for monitor eventhub\_status | +## Related documentation + +Datadog documentation : [https://docs.datadoghq.com/integrations/azure_event_hub/](https://docs.datadoghq.com/integrations/azure_event_hub/) + +Azure metrics documentation : [https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-metrics-azure-monitor](https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-metrics-azure-monitor) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventhub/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventhub/inputs.tf new file mode 100755 index 0000000..bcc9797 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventhub/inputs.tf @@ -0,0 +1,164 @@ +# Global Terraform +variable "environment" { + description = "Architecture environment" + type = string +} + +# Global DataDog +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "eventhub_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Azure Event Hub specific variables + +variable "status_enabled" { + description = "Flag to enable Event Hub status monitor" + type = string + default = "true" +} + +variable "status_extra_tags" { + description = "Extra tags for Event Hub status monitor" + type = list(string) + default = [] +} + +variable "status_message" { + description = "Custom message for Event Hub status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for Event Hub status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for Event Hub status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_requests_rate_enabled" { + description = "Flag to enable Event Hub failed requests monitor" + type = string + default = "true" +} + +variable "failed_requests_rate_extra_tags" { + description = "Extra tags for Event Hub failed requests monitor" + type = list(string) + default = [] +} + +variable "failed_requests_rate_message" { + description = "Custom message for Event Hub failed requests monitor" + type = string + default = "" +} + +variable "failed_requests_rate_time_aggregator" { + description = "Monitor aggregator for Event Hub failed requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "failed_requests_rate_timeframe" { + description = "Monitor timeframe for Event Hub failed requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_requests_rate_thresold_critical" { + description = "Failed requests ratio (percentage) to trigger the critical alert" + default = 90 +} + +variable "failed_requests_rate_thresold_warning" { + description = "Failed requests ratio (percentage) to trigger a warning alert" + default = 50 +} + +variable "errors_rate_enabled" { + description = "Flag to enable Event Hub errors monitor" + type = string + default = "true" +} + +variable "errors_rate_extra_tags" { + description = "Extra tags for Event Hub errors monitor" + type = list(string) + default = [] +} + +variable "errors_rate_message" { + description = "Custom message for Event Hub errors monitor" + type = string + default = "" +} + +variable "errors_rate_time_aggregator" { + description = "Monitor aggregator for Event Hub errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "errors_rate_timeframe" { + description = "Monitor timeframe for Event Hub errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "errors_rate_thresold_critical" { + description = "Errors ratio (percentage) to trigger the critical alert" + default = 90 +} + +variable "errors_rate_thresold_warning" { + description = "Errors ratio (percentage) to trigger a warning alert" + default = 50 +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventhub/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventhub/modules.tf new file mode 100755 index 0000000..15b8884 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventhub/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_eventhub" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventhub/monitors-eventhub.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventhub/monitors-eventhub.tf new file mode 100755 index 0000000..caa6321 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventhub/monitors-eventhub.tf @@ -0,0 +1,90 @@ +resource "datadog_monitor" "eventhub_status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Event Hub is down" + message = coalesce(var.status_message, var.message) + type = "query alert" + + query = < ${var.failed_requests_rate_thresold_critical} +EOQ + + monitor_thresholds { + critical = var.failed_requests_rate_thresold_critical + warning = var.failed_requests_rate_thresold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:eventhub", "team:claranet", "created-by:terraform"], var.failed_requests_rate_extra_tags) +} + +resource "datadog_monitor" "eventhub_errors" { + count = var.errors_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Event Hub too many errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.errors_rate_message, var.message) + type = "query alert" + + query = < ${var.errors_rate_thresold_critical} +EOQ + + monitor_thresholds { + critical = var.errors_rate_thresold_critical + warning = var.errors_rate_thresold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:eventhub", "team:claranet", "created-by:terraform"], var.errors_rate_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventhub/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventhub/outputs.tf new file mode 100755 index 0000000..94646a5 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventhub/outputs.tf @@ -0,0 +1,15 @@ +output "eventhub_errors_id" { + description = "id for monitor eventhub_errors" + value = datadog_monitor.eventhub_errors.*.id +} + +output "eventhub_failed_requests_id" { + description = "id for monitor eventhub_failed_requests" + value = datadog_monitor.eventhub_failed_requests.*.id +} + +output "eventhub_status_id" { + description = "id for monitor eventhub_status" + value = datadog_monitor.eventhub_status.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventhub/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventhub/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/eventhub/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/functions/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/functions/README.md new file mode 100755 index 0000000..5b8bbdd --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/functions/README.md @@ -0,0 +1,99 @@ +# CLOUD AZURE FUNCTIONS DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-functions" { + source = "claranet/monitors/datadog//cloud/azure/functions" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Function App connections count too high +- Function App HTTP 5xx errors too high +- Function App threads count too high + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.function_high_connections_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.function_high_threads_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.function_http_5xx_errors_rate](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [high\_connections\_count\_enabled](#input\_high\_connections\_count\_enabled) | Flag to enable Functions high connections count monitor | `string` | `"true"` | no | +| [high\_connections\_count\_extra\_tags](#input\_high\_connections\_count\_extra\_tags) | Extra tags for Functions high connections count monitor | `list(string)` | `[]` | no | +| [high\_connections\_count\_message](#input\_high\_connections\_count\_message) | Custom message for Functions high connections count monitor | `string` | `""` | no | +| [high\_connections\_count\_threshold\_critical](#input\_high\_connections\_count\_threshold\_critical) | Alerting threshold for Functions high connections count | `number` | `590` | no | +| [high\_connections\_count\_threshold\_warning](#input\_high\_connections\_count\_threshold\_warning) | Warning threshold for Functions high connections count | `number` | `550` | no | +| [high\_connections\_count\_time\_aggregator](#input\_high\_connections\_count\_time\_aggregator) | Monitor aggregator for Functions high connections count [available values: min, max or avg] | `string` | `"min"` | no | +| [high\_connections\_count\_timeframe](#input\_high\_connections\_count\_timeframe) | Monitor timeframe for Functions high connections count [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [high\_threads\_count\_enabled](#input\_high\_threads\_count\_enabled) | Flag to enable Functions high threads count monitor | `string` | `"true"` | no | +| [high\_threads\_count\_extra\_tags](#input\_high\_threads\_count\_extra\_tags) | Extra tags for Functions high threads count monitor | `list(string)` | `[]` | no | +| [high\_threads\_count\_message](#input\_high\_threads\_count\_message) | Custom message for Functions high threads count monitor | `string` | `""` | no | +| [high\_threads\_count\_threshold\_critical](#input\_high\_threads\_count\_threshold\_critical) | Alerting threshold for Functions high threads count | `number` | `510` | no | +| [high\_threads\_count\_threshold\_warning](#input\_high\_threads\_count\_threshold\_warning) | Warning threshold for Functions high threads count | `number` | `490` | no | +| [high\_threads\_count\_time\_aggregator](#input\_high\_threads\_count\_time\_aggregator) | Monitor aggregator for Functions high threads count [available values: min, max or avg] | `string` | `"min"` | no | +| [high\_threads\_count\_timeframe](#input\_high\_threads\_count\_timeframe) | Monitor timeframe for Functions high threads count [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [http\_5xx\_errors\_rate\_enabled](#input\_http\_5xx\_errors\_rate\_enabled) | Flag to enable Functions Http 5xx errors rate monitor | `string` | `"true"` | no | +| [http\_5xx\_errors\_rate\_extra\_tags](#input\_http\_5xx\_errors\_rate\_extra\_tags) | Extra tags for Functions Http 5xx errors rate monitor | `list(string)` | `[]` | no | +| [http\_5xx\_errors\_rate\_message](#input\_http\_5xx\_errors\_rate\_message) | Custom message for Functions Http 5xx errors rate monitor | `string` | `""` | no | +| [http\_5xx\_errors\_rate\_threshold\_critical](#input\_http\_5xx\_errors\_rate\_threshold\_critical) | Alerting threshold for Functions Http 5xx errors rate | `number` | `20` | no | +| [http\_5xx\_errors\_rate\_threshold\_warning](#input\_http\_5xx\_errors\_rate\_threshold\_warning) | Warning threshold for Functions Http 5xx errors rate | `number` | `10` | no | +| [http\_5xx\_errors\_rate\_time\_aggregator](#input\_http\_5xx\_errors\_rate\_time\_aggregator) | Monitor aggregator for Functions Http 5xx errors rate [available values: min, max or avg] | `string` | `"min"` | no | +| [http\_5xx\_errors\_rate\_timeframe](#input\_http\_5xx\_errors\_rate\_timeframe) | Monitor timeframe for Functions Http 5xx errors rate [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [function\_high\_connections\_count\_id](#output\_function\_high\_connections\_count\_id) | id for monitor function\_high\_connections\_count | +| [function\_high\_threads\_count\_id](#output\_function\_high\_threads\_count\_id) | id for monitor function\_high\_threads\_count | +| [function\_http\_5xx\_errors\_rate\_id](#output\_function\_http\_5xx\_errors\_rate\_id) | id for monitor function\_http\_5xx\_errors\_rate | +## Related documentation + +Datadog Azure documentation: [https://docs.datadoghq.com/integrations/azure/](https://docs.datadoghq.com/integrations/azure/) + +Azure Monitor metrics: [https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-supported#microsoftwebsites-functions](https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-supported#microsoftwebsites-functions) + +Azure Functions connections limits: [https://docs.microsoft.com/en-us/azure/azure-functions/manage-connections#connections-limit](https://docs.microsoft.com/en-us/azure/azure-functions/manage-connections#connections-limit) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/functions/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/functions/inputs.tf new file mode 100755 index 0000000..2b76cec --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/functions/inputs.tf @@ -0,0 +1,166 @@ +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# Azure Function App specific variables + +variable "http_5xx_errors_rate_enabled" { + description = "Flag to enable Functions Http 5xx errors rate monitor" + type = string + default = "true" +} + +variable "http_5xx_errors_rate_extra_tags" { + description = "Extra tags for Functions Http 5xx errors rate monitor" + type = list(string) + default = [] +} + +variable "http_5xx_errors_rate_message" { + description = "Custom message for Functions Http 5xx errors rate monitor" + type = string + default = "" +} + +variable "http_5xx_errors_rate_time_aggregator" { + description = "Monitor aggregator for Functions Http 5xx errors rate [available values: min, max or avg]" + type = string + default = "min" +} + +variable "http_5xx_errors_rate_timeframe" { + description = "Monitor timeframe for Functions Http 5xx errors rate [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "http_5xx_errors_rate_threshold_critical" { + default = 20 + description = "Alerting threshold for Functions Http 5xx errors rate" +} + +variable "http_5xx_errors_rate_threshold_warning" { + default = 10 + description = "Warning threshold for Functions Http 5xx errors rate" +} + +variable "high_connections_count_enabled" { + description = "Flag to enable Functions high connections count monitor" + type = string + default = "true" +} + +variable "high_connections_count_extra_tags" { + description = "Extra tags for Functions high connections count monitor" + type = list(string) + default = [] +} + +variable "high_connections_count_message" { + description = "Custom message for Functions high connections count monitor" + type = string + default = "" +} + +variable "high_connections_count_time_aggregator" { + description = "Monitor aggregator for Functions high connections count [available values: min, max or avg]" + type = string + default = "min" +} + +variable "high_connections_count_timeframe" { + description = "Monitor timeframe for Functions high connections count [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "high_connections_count_threshold_critical" { + default = 590 + description = "Alerting threshold for Functions high connections count" +} + +variable "high_connections_count_threshold_warning" { + default = 550 + description = "Warning threshold for Functions high connections count" +} + +variable "high_threads_count_enabled" { + description = "Flag to enable Functions high threads count monitor" + type = string + default = "true" +} + +variable "high_threads_count_extra_tags" { + description = "Extra tags for Functions high threads count monitor" + type = list(string) + default = [] +} + +variable "high_threads_count_message" { + description = "Custom message for Functions high threads count monitor" + type = string + default = "" +} + +variable "high_threads_count_time_aggregator" { + description = "Monitor aggregator for Functions high threads count [available values: min, max or avg]" + type = string + default = "min" +} + +variable "high_threads_count_timeframe" { + description = "Monitor timeframe for Functions high threads count [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "high_threads_count_threshold_critical" { + default = 510 + description = "Alerting threshold for Functions high threads count" +} + +variable "high_threads_count_threshold_warning" { + default = 490 + description = "Warning threshold for Functions high threads count" +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/functions/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/functions/modules.tf new file mode 100755 index 0000000..8d6e1d0 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/functions/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_functions" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/functions/monitors-functions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/functions/monitors-functions.tf new file mode 100755 index 0000000..f54aa18 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/functions/monitors-functions.tf @@ -0,0 +1,85 @@ +resource "datadog_monitor" "function_http_5xx_errors_rate" { + count = var.http_5xx_errors_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Function App HTTP 5xx errors too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.http_5xx_errors_rate_message, var.message) + type = "query alert" + + query = < ${var.http_5xx_errors_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.http_5xx_errors_rate_threshold_warning + critical = var.http_5xx_errors_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 1 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:azure_functions", "team:claranet", "created-by:terraform"], var.http_5xx_errors_rate_extra_tags) +} + +resource "datadog_monitor" "function_high_connections_count" { + count = var.high_connections_count_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Function App connections count too high {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.high_connections_count_message, var.message) + type = "query alert" + + query = < ${var.high_connections_count_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.high_connections_count_threshold_warning + critical = var.high_connections_count_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 1 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:azure_functions", "team:claranet", "created-by:terraform"], var.high_connections_count_extra_tags) +} + +resource "datadog_monitor" "function_high_threads_count" { + count = var.high_threads_count_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Function App threads count too high {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.high_threads_count_message, var.message) + type = "query alert" + + query = < ${var.high_threads_count_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.high_threads_count_threshold_warning + critical = var.high_threads_count_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 1 + include_tags = true + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:azure_functions", "team:claranet", "created-by:terraform"], var.high_threads_count_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/functions/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/functions/outputs.tf new file mode 100755 index 0000000..60481dd --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/functions/outputs.tf @@ -0,0 +1,15 @@ +output "function_high_connections_count_id" { + description = "id for monitor function_high_connections_count" + value = datadog_monitor.function_high_connections_count.*.id +} + +output "function_high_threads_count_id" { + description = "id for monitor function_high_threads_count" + value = datadog_monitor.function_high_threads_count.*.id +} + +output "function_http_5xx_errors_rate_id" { + description = "id for monitor function_http_5xx_errors_rate" + value = datadog_monitor.function_http_5xx_errors_rate.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/functions/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/functions/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/functions/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/iothubs/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/iothubs/README.md new file mode 100755 index 0000000..c119288 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/iothubs/README.md @@ -0,0 +1,203 @@ +# CLOUD AZURE IOTHUBS DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-iothubs" { + source = "claranet/monitors/datadog//cloud/azure/iothubs" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- IOT Hub is down +- IOT Hub Too many c2d methods failure +- IOT Hub Too many c2d twin read failure +- IOT Hub Too many c2d twin update failure +- IOT Hub Too many d2c telemetry egress dropped +- IOT Hub Too many d2c telemetry egress invalid +- IOT Hub Too many d2c telemetry egress orphaned +- IOT Hub Too many d2c telemetry ingress not sent +- IOT Hub Too many d2c twin read failure +- IOT Hub Too many d2c twin update failure +- IOT Hub Too many jobs failed +- IOT Hub Too many list_jobs failure +- IOT Hub Too many query_jobs failed +- IOT Hub Total devices is wrong + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_c2d_methods_failed](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_c2d_twin_read_failed](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_c2d_twin_update_failed](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_d2c_telemetry_egress_dropped](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_d2c_telemetry_egress_invalid](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_d2c_telemetry_egress_orphaned](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_d2c_telemetry_ingress_nosent](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_d2c_twin_read_failed](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_d2c_twin_update_failed](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_jobs_failed](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_list_jobs_failed](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.too_many_query_jobs_failed](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.total_devices](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [dropped\_d2c\_telemetry\_egress\_enabled](#input\_dropped\_d2c\_telemetry\_egress\_enabled) | Flag to enable IoT Hub dropped d2c telemetry monitor | `string` | `"true"` | no | +| [dropped\_d2c\_telemetry\_egress\_extra\_tags](#input\_dropped\_d2c\_telemetry\_egress\_extra\_tags) | Extra tags for IoT Hub dropped d2c telemetry monitor | `list(string)` | `[]` | no | +| [dropped\_d2c\_telemetry\_egress\_message](#input\_dropped\_d2c\_telemetry\_egress\_message) | Custom message for IoT Hub dropped d2c telemetry monitor | `string` | `""` | no | +| [dropped\_d2c\_telemetry\_egress\_rate\_threshold\_critical](#input\_dropped\_d2c\_telemetry\_egress\_rate\_threshold\_critical) | D2C Telemetry Dropped limit (critical threshold) | `number` | `90` | no | +| [dropped\_d2c\_telemetry\_egress\_rate\_threshold\_warning](#input\_dropped\_d2c\_telemetry\_egress\_rate\_threshold\_warning) | D2C Telemetry Dropped limit (warning threshold) | `number` | `50` | no | +| [dropped\_d2c\_telemetry\_egress\_time\_aggregator](#input\_dropped\_d2c\_telemetry\_egress\_time\_aggregator) | Monitor aggregator for IoT Hub dropped d2c telemetry [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [dropped\_d2c\_telemetry\_egress\_timeframe](#input\_dropped\_d2c\_telemetry\_egress\_timeframe) | Monitor timeframe for IoT Hub dropped d2c telemetry [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [failed\_c2d\_methods\_rate\_enabled](#input\_failed\_c2d\_methods\_rate\_enabled) | Flag to enable IoT Hub failed c2d methods monitor | `string` | `"true"` | no | +| [failed\_c2d\_methods\_rate\_extra\_tags](#input\_failed\_c2d\_methods\_rate\_extra\_tags) | Extra tags for IoT Hub failed c2d methods monitor | `list(string)` | `[]` | no | +| [failed\_c2d\_methods\_rate\_message](#input\_failed\_c2d\_methods\_rate\_message) | Custom message for IoT Hub failed c2d method monitor | `string` | `""` | no | +| [failed\_c2d\_methods\_rate\_threshold\_critical](#input\_failed\_c2d\_methods\_rate\_threshold\_critical) | C2D Methods Failed rate limit (critical threshold) | `number` | `90` | no | +| [failed\_c2d\_methods\_rate\_threshold\_warning](#input\_failed\_c2d\_methods\_rate\_threshold\_warning) | C2D Methods Failed rate limit (warning threshold) | `number` | `50` | no | +| [failed\_c2d\_methods\_rate\_time\_aggregator](#input\_failed\_c2d\_methods\_rate\_time\_aggregator) | Monitor aggregator for IoT Hub failed c2d method [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [failed\_c2d\_methods\_rate\_timeframe](#input\_failed\_c2d\_methods\_rate\_timeframe) | Monitor timeframe for IoT Hub failed c2d method [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [failed\_c2d\_twin\_read\_rate\_enabled](#input\_failed\_c2d\_twin\_read\_rate\_enabled) | Flag to enable IoT Hub failed c2d twin read monitor | `string` | `"true"` | no | +| [failed\_c2d\_twin\_read\_rate\_extra\_tags](#input\_failed\_c2d\_twin\_read\_rate\_extra\_tags) | Extra tags for IoT Hub failed c2d twin read monitor | `list(string)` | `[]` | no | +| [failed\_c2d\_twin\_read\_rate\_message](#input\_failed\_c2d\_twin\_read\_rate\_message) | Custom message for IoT Hub failed c2d twin read monitor | `string` | `""` | no | +| [failed\_c2d\_twin\_read\_rate\_threshold\_critical](#input\_failed\_c2d\_twin\_read\_rate\_threshold\_critical) | C2D Twin Read Failed rate limit (critical threshold) | `number` | `90` | no | +| [failed\_c2d\_twin\_read\_rate\_threshold\_warning](#input\_failed\_c2d\_twin\_read\_rate\_threshold\_warning) | C2D Twin Read Failed rate limit (warning threshold) | `number` | `50` | no | +| [failed\_c2d\_twin\_read\_rate\_time\_aggregator](#input\_failed\_c2d\_twin\_read\_rate\_time\_aggregator) | Monitor aggregator for IoT Hub failed c2d twin read [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [failed\_c2d\_twin\_read\_rate\_timeframe](#input\_failed\_c2d\_twin\_read\_rate\_timeframe) | Monitor timeframe for IoT Hub failed c2d twin read [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [failed\_c2d\_twin\_update\_rate\_enabled](#input\_failed\_c2d\_twin\_update\_rate\_enabled) | Flag to enable IoT Hub failed c2d twin update monitor | `string` | `"true"` | no | +| [failed\_c2d\_twin\_update\_rate\_extra\_tags](#input\_failed\_c2d\_twin\_update\_rate\_extra\_tags) | Extra tags for IoT Hub failed c2d twin update monitor | `list(string)` | `[]` | no | +| [failed\_c2d\_twin\_update\_rate\_message](#input\_failed\_c2d\_twin\_update\_rate\_message) | Custom message for IoT Hub failed c2d twin update monitor | `string` | `""` | no | +| [failed\_c2d\_twin\_update\_rate\_threshold\_critical](#input\_failed\_c2d\_twin\_update\_rate\_threshold\_critical) | C2D Twin Update Failed rate limit (critical threshold) | `number` | `90` | no | +| [failed\_c2d\_twin\_update\_rate\_threshold\_warning](#input\_failed\_c2d\_twin\_update\_rate\_threshold\_warning) | C2D Twin Update Failed rate limit (warning threshold) | `number` | `50` | no | +| [failed\_c2d\_twin\_update\_rate\_time\_aggregator](#input\_failed\_c2d\_twin\_update\_rate\_time\_aggregator) | Monitor aggregator for IoT Hub failed c2d twin update [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [failed\_c2d\_twin\_update\_rate\_timeframe](#input\_failed\_c2d\_twin\_update\_rate\_timeframe) | Monitor timeframe for IoT Hub failed c2d twin update [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [failed\_d2c\_twin\_read\_rate\_enabled](#input\_failed\_d2c\_twin\_read\_rate\_enabled) | Flag to enable IoT Hub failed d2c twin read monitor | `string` | `"true"` | no | +| [failed\_d2c\_twin\_read\_rate\_extra\_tags](#input\_failed\_d2c\_twin\_read\_rate\_extra\_tags) | Extra tags for IoT Hub failed d2c twin read monitor | `list(string)` | `[]` | no | +| [failed\_d2c\_twin\_read\_rate\_message](#input\_failed\_d2c\_twin\_read\_rate\_message) | Custom message for IoT Hub failed d2c twin read monitor | `string` | `""` | no | +| [failed\_d2c\_twin\_read\_rate\_threshold\_critical](#input\_failed\_d2c\_twin\_read\_rate\_threshold\_critical) | D2C Twin Read Failed rate limit (critical threshold) | `number` | `90` | no | +| [failed\_d2c\_twin\_read\_rate\_threshold\_warning](#input\_failed\_d2c\_twin\_read\_rate\_threshold\_warning) | D2C Twin Read Failed rate limit (warning threshold) | `number` | `50` | no | +| [failed\_d2c\_twin\_read\_rate\_time\_aggregator](#input\_failed\_d2c\_twin\_read\_rate\_time\_aggregator) | Monitor aggregator for IoT Hub failed d2c twin read [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [failed\_d2c\_twin\_read\_rate\_timeframe](#input\_failed\_d2c\_twin\_read\_rate\_timeframe) | Monitor timeframe for IoT Hub failed d2c twin read [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [failed\_d2c\_twin\_update\_rate\_enabled](#input\_failed\_d2c\_twin\_update\_rate\_enabled) | Flag to enable IoT Hub failed d2c twin update monitor | `string` | `"true"` | no | +| [failed\_d2c\_twin\_update\_rate\_extra\_tags](#input\_failed\_d2c\_twin\_update\_rate\_extra\_tags) | Extra tags for IoT Hub failed d2c twin update monitor | `list(string)` | `[]` | no | +| [failed\_d2c\_twin\_update\_rate\_message](#input\_failed\_d2c\_twin\_update\_rate\_message) | Custom message for IoT Hub failed d2c twin update monitor | `string` | `""` | no | +| [failed\_d2c\_twin\_update\_rate\_threshold\_critical](#input\_failed\_d2c\_twin\_update\_rate\_threshold\_critical) | D2C Twin Update Failed rate limit (critical threshold) | `number` | `90` | no | +| [failed\_d2c\_twin\_update\_rate\_threshold\_warning](#input\_failed\_d2c\_twin\_update\_rate\_threshold\_warning) | D2C Twin Update Failed rate limit (warning threshold) | `number` | `50` | no | +| [failed\_d2c\_twin\_update\_rate\_time\_aggregator](#input\_failed\_d2c\_twin\_update\_rate\_time\_aggregator) | Monitor aggregator for IoT Hub failed d2c twin update [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [failed\_d2c\_twin\_update\_rate\_timeframe](#input\_failed\_d2c\_twin\_update\_rate\_timeframe) | Monitor timeframe for IoT Hub failed d2c twin update [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [failed\_jobs\_rate\_enabled](#input\_failed\_jobs\_rate\_enabled) | Flag to enable IoT Hub failed jobs monitor | `string` | `"true"` | no | +| [failed\_jobs\_rate\_extra\_tags](#input\_failed\_jobs\_rate\_extra\_tags) | Extra tags for IoT Hub failed jobs monitor | `list(string)` | `[]` | no | +| [failed\_jobs\_rate\_message](#input\_failed\_jobs\_rate\_message) | Custom message for IoT Hub failed jobs monitor | `string` | `""` | no | +| [failed\_jobs\_rate\_threshold\_critical](#input\_failed\_jobs\_rate\_threshold\_critical) | Jobs Failed rate limit (critical threshold) | `number` | `90` | no | +| [failed\_jobs\_rate\_threshold\_warning](#input\_failed\_jobs\_rate\_threshold\_warning) | Jobs Failed rate limit (warning threshold) | `number` | `50` | no | +| [failed\_jobs\_rate\_time\_aggregator](#input\_failed\_jobs\_rate\_time\_aggregator) | Monitor aggregator for IoT Hub failed jobs [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [failed\_jobs\_rate\_timeframe](#input\_failed\_jobs\_rate\_timeframe) | Monitor timeframe for IoT Hub failed jobs [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [failed\_listjobs\_rate\_enabled](#input\_failed\_listjobs\_rate\_enabled) | Flag to enable IoT Hub failed list jobs monitor | `string` | `"true"` | no | +| [failed\_listjobs\_rate\_extra\_tags](#input\_failed\_listjobs\_rate\_extra\_tags) | Extra tags for IoT Hub failed list jobs monitor | `list(string)` | `[]` | no | +| [failed\_listjobs\_rate\_message](#input\_failed\_listjobs\_rate\_message) | Custom message for IoT Hub failed list jobs monitor | `string` | `""` | no | +| [failed\_listjobs\_rate\_threshold\_critical](#input\_failed\_listjobs\_rate\_threshold\_critical) | ListJobs Failed rate limit (critical threshold) | `number` | `90` | no | +| [failed\_listjobs\_rate\_threshold\_warning](#input\_failed\_listjobs\_rate\_threshold\_warning) | ListJobs Failed rate limit (warning threshold) | `number` | `50` | no | +| [failed\_listjobs\_rate\_time\_aggregator](#input\_failed\_listjobs\_rate\_time\_aggregator) | Monitor aggregator for IoT Hub failed list jobs [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [failed\_listjobs\_rate\_timeframe](#input\_failed\_listjobs\_rate\_timeframe) | Monitor timeframe for IoT Hub failed list jobs [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [failed\_queryjobs\_rate\_enabled](#input\_failed\_queryjobs\_rate\_enabled) | Flag to enable IoT Hub failed query jobs monitor | `string` | `"true"` | no | +| [failed\_queryjobs\_rate\_extra\_tags](#input\_failed\_queryjobs\_rate\_extra\_tags) | Extra tags for IoT Hub failed query jobs monitor | `list(string)` | `[]` | no | +| [failed\_queryjobs\_rate\_message](#input\_failed\_queryjobs\_rate\_message) | Custom message for IoT Hub failed query jobs monitor | `string` | `""` | no | +| [failed\_queryjobs\_rate\_threshold\_critical](#input\_failed\_queryjobs\_rate\_threshold\_critical) | QueryJobs Failed rate limit (critical threshold) | `number` | `90` | no | +| [failed\_queryjobs\_rate\_threshold\_warning](#input\_failed\_queryjobs\_rate\_threshold\_warning) | QueryJobs Failed rate limit (warning threshold) | `number` | `50` | no | +| [failed\_queryjobs\_rate\_time\_aggregator](#input\_failed\_queryjobs\_rate\_time\_aggregator) | Monitor aggregator for IoT Hub failed query jobs [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [failed\_queryjobs\_rate\_timeframe](#input\_failed\_queryjobs\_rate\_timeframe) | Monitor timeframe for IoT Hub failed query jobs [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [invalid\_d2c\_telemetry\_egress\_enabled](#input\_invalid\_d2c\_telemetry\_egress\_enabled) | Flag to enable IoT Hub invalid d2c telemetry monitor | `string` | `"true"` | no | +| [invalid\_d2c\_telemetry\_egress\_extra\_tags](#input\_invalid\_d2c\_telemetry\_egress\_extra\_tags) | Extra tags for IoT Hub invalid d2c telemetry monitor | `list(string)` | `[]` | no | +| [invalid\_d2c\_telemetry\_egress\_message](#input\_invalid\_d2c\_telemetry\_egress\_message) | Custom message for IoT Hub invalid d2c telemetry monitor | `string` | `""` | no | +| [invalid\_d2c\_telemetry\_egress\_rate\_threshold\_critical](#input\_invalid\_d2c\_telemetry\_egress\_rate\_threshold\_critical) | D2C Telemetry Invalid limit (critical threshold) | `number` | `90` | no | +| [invalid\_d2c\_telemetry\_egress\_rate\_threshold\_warning](#input\_invalid\_d2c\_telemetry\_egress\_rate\_threshold\_warning) | D2C Telemetry Invalid limit (warning threshold) | `number` | `50` | no | +| [invalid\_d2c\_telemetry\_egress\_time\_aggregator](#input\_invalid\_d2c\_telemetry\_egress\_time\_aggregator) | Monitor aggregator for IoT Hub invalid d2c telemetry [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [invalid\_d2c\_telemetry\_egress\_timeframe](#input\_invalid\_d2c\_telemetry\_egress\_timeframe) | Monitor timeframe for IoT Hub invalid d2c telemetry [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [orphaned\_d2c\_telemetry\_egress\_enabled](#input\_orphaned\_d2c\_telemetry\_egress\_enabled) | Flag to enable IoT Hub orphaned d2c telemetry monitor | `string` | `"true"` | no | +| [orphaned\_d2c\_telemetry\_egress\_extra\_tags](#input\_orphaned\_d2c\_telemetry\_egress\_extra\_tags) | Extra tags for IoT Hub orphaned d2c telemetry monitor | `list(string)` | `[]` | no | +| [orphaned\_d2c\_telemetry\_egress\_message](#input\_orphaned\_d2c\_telemetry\_egress\_message) | Custom message for IoT Hub orphaned d2c telemetry monitor | `string` | `""` | no | +| [orphaned\_d2c\_telemetry\_egress\_rate\_threshold\_critical](#input\_orphaned\_d2c\_telemetry\_egress\_rate\_threshold\_critical) | D2C Telemetry Orphaned limit (critical threshold) | `number` | `90` | no | +| [orphaned\_d2c\_telemetry\_egress\_rate\_threshold\_warning](#input\_orphaned\_d2c\_telemetry\_egress\_rate\_threshold\_warning) | D2C Telemetry Orphaned limit (warning threshold) | `number` | `50` | no | +| [orphaned\_d2c\_telemetry\_egress\_time\_aggregator](#input\_orphaned\_d2c\_telemetry\_egress\_time\_aggregator) | Monitor aggregator for IoT Hub orphaned d2c telemetry [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [orphaned\_d2c\_telemetry\_egress\_timeframe](#input\_orphaned\_d2c\_telemetry\_egress\_timeframe) | Monitor timeframe for IoT Hub orphaned d2c telemetry [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable IoT Hub status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for IoT Hub status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for IoT Hub status monitor | `string` | `""` | no | +| [status\_no\_data\_timeframe](#input\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for IoT Hub status [available values: min, max, sum or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for IoT Hub status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [too\_many\_d2c\_telemetry\_ingress\_nosent\_enabled](#input\_too\_many\_d2c\_telemetry\_ingress\_nosent\_enabled) | Flag to enable IoT Hub unsent d2c telemetry monitor | `string` | `"true"` | no | +| [too\_many\_d2c\_telemetry\_ingress\_nosent\_extra\_tags](#input\_too\_many\_d2c\_telemetry\_ingress\_nosent\_extra\_tags) | Extra tags for IoT Hub unsent d2c telemetry monitor | `list(string)` | `[]` | no | +| [too\_many\_d2c\_telemetry\_ingress\_nosent\_message](#input\_too\_many\_d2c\_telemetry\_ingress\_nosent\_message) | Custom message for IoT Hub unsent d2c telemetry monitor | `string` | `""` | no | +| [too\_many\_d2c\_telemetry\_ingress\_nosent\_rate\_threshold\_critical](#input\_too\_many\_d2c\_telemetry\_ingress\_nosent\_rate\_threshold\_critical) | D2C Telemetry ingress not sent limit (critical threshold) | `number` | `20` | no | +| [too\_many\_d2c\_telemetry\_ingress\_nosent\_rate\_threshold\_warning](#input\_too\_many\_d2c\_telemetry\_ingress\_nosent\_rate\_threshold\_warning) | D2C Telemetry ingress not sent limit (warning threshold) | `number` | `10` | no | +| [too\_many\_d2c\_telemetry\_ingress\_nosent\_timeframe](#input\_too\_many\_d2c\_telemetry\_ingress\_nosent\_timeframe) | Monitor timeframe for IoT Hub unsent d2c telemetry [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [total\_devices\_enabled](#input\_total\_devices\_enabled) | Flag to enable IoT Hub total devices monitor | `string` | `"true"` | no | +| [total\_devices\_extra\_tags](#input\_total\_devices\_extra\_tags) | Extra tags for IoT Hub total devices monitor | `list(string)` | `[]` | no | +| [total\_devices\_message](#input\_total\_devices\_message) | Custom message for IoT Hub total devices monitor | `string` | `""` | no | +| [total\_devices\_time\_aggregator](#input\_total\_devices\_time\_aggregator) | Monitor aggregator for IoT Hub total devices [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [total\_devices\_timeframe](#input\_total\_devices\_timeframe) | Monitor timeframe for IoT Hub total devices [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [status\_id](#output\_status\_id) | id for monitor status | +| [too\_many\_c2d\_methods\_failed\_id](#output\_too\_many\_c2d\_methods\_failed\_id) | id for monitor too\_many\_c2d\_methods\_failed | +| [too\_many\_c2d\_twin\_read\_failed\_id](#output\_too\_many\_c2d\_twin\_read\_failed\_id) | id for monitor too\_many\_c2d\_twin\_read\_failed | +| [too\_many\_c2d\_twin\_update\_failed\_id](#output\_too\_many\_c2d\_twin\_update\_failed\_id) | id for monitor too\_many\_c2d\_twin\_update\_failed | +| [too\_many\_d2c\_telemetry\_egress\_dropped\_id](#output\_too\_many\_d2c\_telemetry\_egress\_dropped\_id) | id for monitor too\_many\_d2c\_telemetry\_egress\_dropped | +| [too\_many\_d2c\_telemetry\_egress\_invalid\_id](#output\_too\_many\_d2c\_telemetry\_egress\_invalid\_id) | id for monitor too\_many\_d2c\_telemetry\_egress\_invalid | +| [too\_many\_d2c\_telemetry\_egress\_orphaned\_id](#output\_too\_many\_d2c\_telemetry\_egress\_orphaned\_id) | id for monitor too\_many\_d2c\_telemetry\_egress\_orphaned | +| [too\_many\_d2c\_telemetry\_ingress\_nosent\_id](#output\_too\_many\_d2c\_telemetry\_ingress\_nosent\_id) | id for monitor too\_many\_d2c\_telemetry\_ingress\_nosent | +| [too\_many\_d2c\_twin\_read\_failed\_id](#output\_too\_many\_d2c\_twin\_read\_failed\_id) | id for monitor too\_many\_d2c\_twin\_read\_failed | +| [too\_many\_d2c\_twin\_update\_failed\_id](#output\_too\_many\_d2c\_twin\_update\_failed\_id) | id for monitor too\_many\_d2c\_twin\_update\_failed | +| [too\_many\_jobs\_failed\_id](#output\_too\_many\_jobs\_failed\_id) | id for monitor too\_many\_jobs\_failed | +| [too\_many\_list\_jobs\_failed\_id](#output\_too\_many\_list\_jobs\_failed\_id) | id for monitor too\_many\_list\_jobs\_failed | +| [too\_many\_query\_jobs\_failed\_id](#output\_too\_many\_query\_jobs\_failed\_id) | id for monitor too\_many\_query\_jobs\_failed | +| [total\_devices\_id](#output\_total\_devices\_id) | id for monitor total\_devices | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure_iot_hub](https://docs.datadoghq.com/integrations/azure_iot_hub) + +Azure IOT Hubs metrics documentation: [https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-monitor-resource-health](https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-monitor-resource-health) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/iothubs/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/iothubs/inputs.tf new file mode 100755 index 0000000..0a5e90e --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/iothubs/inputs.tf @@ -0,0 +1,587 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# IOT Hub specific variables + +variable "status_enabled" { + description = "Flag to enable IoT Hub status monitor" + type = string + default = "true" +} + +variable "status_extra_tags" { + description = "Extra tags for IoT Hub status monitor" + type = list(string) + default = [] +} + +variable "status_message" { + description = "Custom message for IoT Hub status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for IoT Hub status [available values: min, max, sum or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for IoT Hub status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "total_devices_enabled" { + description = "Flag to enable IoT Hub total devices monitor" + type = string + default = "true" +} + +variable "total_devices_extra_tags" { + description = "Extra tags for IoT Hub total devices monitor" + type = list(string) + default = [] +} + +variable "total_devices_message" { + description = "Custom message for IoT Hub total devices monitor" + type = string + default = "" +} + +variable "total_devices_time_aggregator" { + description = "Monitor aggregator for IoT Hub total devices [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "total_devices_timeframe" { + description = "Monitor timeframe for IoT Hub total devices [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "too_many_d2c_telemetry_ingress_nosent_enabled" { + description = "Flag to enable IoT Hub unsent d2c telemetry monitor" + type = string + default = "true" +} + +variable "too_many_d2c_telemetry_ingress_nosent_extra_tags" { + description = "Extra tags for IoT Hub unsent d2c telemetry monitor" + type = list(string) + default = [] +} + +variable "too_many_d2c_telemetry_ingress_nosent_message" { + description = "Custom message for IoT Hub unsent d2c telemetry monitor" + type = string + default = "" +} + +variable "too_many_d2c_telemetry_ingress_nosent_timeframe" { + description = "Monitor timeframe for IoT Hub unsent d2c telemetry [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_jobs_rate_enabled" { + description = "Flag to enable IoT Hub failed jobs monitor" + type = string + default = "true" +} + +variable "failed_jobs_rate_extra_tags" { + description = "Extra tags for IoT Hub failed jobs monitor" + type = list(string) + default = [] +} + +variable "failed_jobs_rate_message" { + description = "Custom message for IoT Hub failed jobs monitor" + type = string + default = "" +} + +variable "failed_jobs_rate_time_aggregator" { + description = "Monitor aggregator for IoT Hub failed jobs [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "failed_jobs_rate_timeframe" { + description = "Monitor timeframe for IoT Hub failed jobs [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_jobs_rate_threshold_warning" { + description = "Jobs Failed rate limit (warning threshold)" + default = 50 +} + +variable "failed_jobs_rate_threshold_critical" { + description = "Jobs Failed rate limit (critical threshold)" + default = 90 +} + +variable "failed_listjobs_rate_enabled" { + description = "Flag to enable IoT Hub failed list jobs monitor" + type = string + default = "true" +} + +variable "failed_listjobs_rate_extra_tags" { + description = "Extra tags for IoT Hub failed list jobs monitor" + type = list(string) + default = [] +} + +variable "failed_listjobs_rate_message" { + description = "Custom message for IoT Hub failed list jobs monitor" + type = string + default = "" +} + +variable "failed_listjobs_rate_time_aggregator" { + description = "Monitor aggregator for IoT Hub failed list jobs [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "failed_listjobs_rate_timeframe" { + description = "Monitor timeframe for IoT Hub failed list jobs [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_listjobs_rate_threshold_warning" { + description = "ListJobs Failed rate limit (warning threshold)" + default = 50 +} + +variable "failed_listjobs_rate_threshold_critical" { + description = "ListJobs Failed rate limit (critical threshold)" + default = 90 +} + +variable "failed_queryjobs_rate_enabled" { + description = "Flag to enable IoT Hub failed query jobs monitor" + type = string + default = "true" +} + +variable "failed_queryjobs_rate_extra_tags" { + description = "Extra tags for IoT Hub failed query jobs monitor" + type = list(string) + default = [] +} + +variable "failed_queryjobs_rate_message" { + description = "Custom message for IoT Hub failed query jobs monitor" + type = string + default = "" +} + +variable "failed_queryjobs_rate_time_aggregator" { + description = "Monitor aggregator for IoT Hub failed query jobs [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "failed_queryjobs_rate_timeframe" { + description = "Monitor timeframe for IoT Hub failed query jobs [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_queryjobs_rate_threshold_warning" { + description = "QueryJobs Failed rate limit (warning threshold)" + default = 50 +} + +variable "failed_queryjobs_rate_threshold_critical" { + description = "QueryJobs Failed rate limit (critical threshold)" + default = 90 +} + +variable "failed_c2d_methods_rate_enabled" { + description = "Flag to enable IoT Hub failed c2d methods monitor" + type = string + default = "true" +} + +variable "failed_c2d_methods_rate_extra_tags" { + description = "Extra tags for IoT Hub failed c2d methods monitor" + type = list(string) + default = [] +} + +variable "failed_c2d_methods_rate_message" { + description = "Custom message for IoT Hub failed c2d method monitor" + type = string + default = "" +} + +variable "failed_c2d_methods_rate_time_aggregator" { + description = "Monitor aggregator for IoT Hub failed c2d method [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "failed_c2d_methods_rate_timeframe" { + description = "Monitor timeframe for IoT Hub failed c2d method [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_c2d_methods_rate_threshold_warning" { + description = "C2D Methods Failed rate limit (warning threshold)" + default = 50 +} + +variable "failed_c2d_methods_rate_threshold_critical" { + description = "C2D Methods Failed rate limit (critical threshold)" + default = 90 +} + +variable "failed_c2d_twin_read_rate_enabled" { + description = "Flag to enable IoT Hub failed c2d twin read monitor" + type = string + default = "true" +} + +variable "failed_c2d_twin_read_rate_extra_tags" { + description = "Extra tags for IoT Hub failed c2d twin read monitor" + type = list(string) + default = [] +} + +variable "failed_c2d_twin_read_rate_message" { + description = "Custom message for IoT Hub failed c2d twin read monitor" + type = string + default = "" +} + +variable "failed_c2d_twin_read_rate_time_aggregator" { + description = "Monitor aggregator for IoT Hub failed c2d twin read [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "failed_c2d_twin_read_rate_timeframe" { + description = "Monitor timeframe for IoT Hub failed c2d twin read [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_c2d_twin_read_rate_threshold_warning" { + description = "C2D Twin Read Failed rate limit (warning threshold)" + default = 50 +} + +variable "failed_c2d_twin_read_rate_threshold_critical" { + description = "C2D Twin Read Failed rate limit (critical threshold)" + default = 90 +} + +variable "failed_c2d_twin_update_rate_enabled" { + description = "Flag to enable IoT Hub failed c2d twin update monitor" + type = string + default = "true" +} + +variable "failed_c2d_twin_update_rate_extra_tags" { + description = "Extra tags for IoT Hub failed c2d twin update monitor" + type = list(string) + default = [] +} + +variable "failed_c2d_twin_update_rate_message" { + description = "Custom message for IoT Hub failed c2d twin update monitor" + type = string + default = "" +} + +variable "failed_c2d_twin_update_rate_time_aggregator" { + description = "Monitor aggregator for IoT Hub failed c2d twin update [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "failed_c2d_twin_update_rate_timeframe" { + description = "Monitor timeframe for IoT Hub failed c2d twin update [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_c2d_twin_update_rate_threshold_warning" { + description = "C2D Twin Update Failed rate limit (warning threshold)" + default = 50 +} + +variable "failed_c2d_twin_update_rate_threshold_critical" { + description = "C2D Twin Update Failed rate limit (critical threshold)" + default = 90 +} + +variable "failed_d2c_twin_read_rate_enabled" { + description = "Flag to enable IoT Hub failed d2c twin read monitor" + type = string + default = "true" +} + +variable "failed_d2c_twin_read_rate_extra_tags" { + description = "Extra tags for IoT Hub failed d2c twin read monitor" + type = list(string) + default = [] +} + +variable "failed_d2c_twin_read_rate_message" { + description = "Custom message for IoT Hub failed d2c twin read monitor" + type = string + default = "" +} + +variable "failed_d2c_twin_read_rate_time_aggregator" { + description = "Monitor aggregator for IoT Hub failed d2c twin read [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "failed_d2c_twin_read_rate_timeframe" { + description = "Monitor timeframe for IoT Hub failed d2c twin read [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_d2c_twin_read_rate_threshold_warning" { + description = "D2C Twin Read Failed rate limit (warning threshold)" + default = 50 +} + +variable "failed_d2c_twin_read_rate_threshold_critical" { + description = "D2C Twin Read Failed rate limit (critical threshold)" + default = 90 +} + +variable "failed_d2c_twin_update_rate_enabled" { + description = "Flag to enable IoT Hub failed d2c twin update monitor" + type = string + default = "true" +} + +variable "failed_d2c_twin_update_rate_extra_tags" { + description = "Extra tags for IoT Hub failed d2c twin update monitor" + type = list(string) + default = [] +} + +variable "failed_d2c_twin_update_rate_message" { + description = "Custom message for IoT Hub failed d2c twin update monitor" + type = string + default = "" +} + +variable "failed_d2c_twin_update_rate_time_aggregator" { + description = "Monitor aggregator for IoT Hub failed d2c twin update [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "failed_d2c_twin_update_rate_timeframe" { + description = "Monitor timeframe for IoT Hub failed d2c twin update [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_d2c_twin_update_rate_threshold_warning" { + description = "D2C Twin Update Failed rate limit (warning threshold)" + default = 50 +} + +variable "failed_d2c_twin_update_rate_threshold_critical" { + description = "D2C Twin Update Failed rate limit (critical threshold)" + default = 90 +} + +variable "dropped_d2c_telemetry_egress_enabled" { + description = "Flag to enable IoT Hub dropped d2c telemetry monitor" + type = string + default = "true" +} + +variable "dropped_d2c_telemetry_egress_extra_tags" { + description = "Extra tags for IoT Hub dropped d2c telemetry monitor" + type = list(string) + default = [] +} + +variable "dropped_d2c_telemetry_egress_message" { + description = "Custom message for IoT Hub dropped d2c telemetry monitor" + type = string + default = "" +} + +variable "dropped_d2c_telemetry_egress_time_aggregator" { + description = "Monitor aggregator for IoT Hub dropped d2c telemetry [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "dropped_d2c_telemetry_egress_timeframe" { + description = "Monitor timeframe for IoT Hub dropped d2c telemetry [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "dropped_d2c_telemetry_egress_rate_threshold_warning" { + description = "D2C Telemetry Dropped limit (warning threshold)" + default = 50 +} + +variable "dropped_d2c_telemetry_egress_rate_threshold_critical" { + description = "D2C Telemetry Dropped limit (critical threshold)" + default = 90 +} + +variable "orphaned_d2c_telemetry_egress_enabled" { + description = "Flag to enable IoT Hub orphaned d2c telemetry monitor" + type = string + default = "true" +} + +variable "orphaned_d2c_telemetry_egress_extra_tags" { + description = "Extra tags for IoT Hub orphaned d2c telemetry monitor" + type = list(string) + default = [] +} + +variable "orphaned_d2c_telemetry_egress_message" { + description = "Custom message for IoT Hub orphaned d2c telemetry monitor" + type = string + default = "" +} + +variable "orphaned_d2c_telemetry_egress_time_aggregator" { + description = "Monitor aggregator for IoT Hub orphaned d2c telemetry [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "orphaned_d2c_telemetry_egress_timeframe" { + description = "Monitor timeframe for IoT Hub orphaned d2c telemetry [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "orphaned_d2c_telemetry_egress_rate_threshold_warning" { + description = "D2C Telemetry Orphaned limit (warning threshold)" + default = 50 +} + +variable "orphaned_d2c_telemetry_egress_rate_threshold_critical" { + description = "D2C Telemetry Orphaned limit (critical threshold)" + default = 90 +} + +variable "invalid_d2c_telemetry_egress_enabled" { + description = "Flag to enable IoT Hub invalid d2c telemetry monitor" + type = string + default = "true" +} + +variable "invalid_d2c_telemetry_egress_extra_tags" { + description = "Extra tags for IoT Hub invalid d2c telemetry monitor" + type = list(string) + default = [] +} + +variable "invalid_d2c_telemetry_egress_message" { + description = "Custom message for IoT Hub invalid d2c telemetry monitor" + type = string + default = "" +} + +variable "invalid_d2c_telemetry_egress_time_aggregator" { + description = "Monitor aggregator for IoT Hub invalid d2c telemetry [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "invalid_d2c_telemetry_egress_timeframe" { + description = "Monitor timeframe for IoT Hub invalid d2c telemetry [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "invalid_d2c_telemetry_egress_rate_threshold_warning" { + description = "D2C Telemetry Invalid limit (warning threshold)" + default = 50 +} + +variable "invalid_d2c_telemetry_egress_rate_threshold_critical" { + description = "D2C Telemetry Invalid limit (critical threshold)" + default = 90 +} + +variable "too_many_d2c_telemetry_ingress_nosent_rate_threshold_critical" { + description = "D2C Telemetry ingress not sent limit (critical threshold)" + default = 20 +} + +variable "too_many_d2c_telemetry_ingress_nosent_rate_threshold_warning" { + description = "D2C Telemetry ingress not sent limit (warning threshold)" + default = 10 +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/iothubs/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/iothubs/modules.tf new file mode 100755 index 0000000..887245d --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/iothubs/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_iothubs" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/iothubs/monitors-iothubs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/iothubs/monitors-iothubs.tf new file mode 100755 index 0000000..a104616 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/iothubs/monitors-iothubs.tf @@ -0,0 +1,451 @@ +resource "datadog_monitor" "too_many_jobs_failed" { + count = var.failed_jobs_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub Too many jobs failed {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.failed_jobs_rate_message, var.message) + type = "query alert" + + query = < ${var.failed_jobs_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.failed_jobs_rate_threshold_warning + critical = var.failed_jobs_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.failed_jobs_rate_extra_tags) +} + +resource "datadog_monitor" "too_many_list_jobs_failed" { + count = var.failed_listjobs_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub Too many list_jobs failure {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.failed_listjobs_rate_message, var.message) + type = "query alert" + + query = < ${var.failed_listjobs_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.failed_listjobs_rate_threshold_warning + critical = var.failed_listjobs_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.failed_listjobs_rate_extra_tags) +} + +resource "datadog_monitor" "too_many_query_jobs_failed" { + count = var.failed_queryjobs_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub Too many query_jobs failed {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.failed_queryjobs_rate_message, var.message) + type = "query alert" + + query = < ${var.failed_queryjobs_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.failed_queryjobs_rate_threshold_warning + critical = var.failed_queryjobs_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.failed_queryjobs_rate_extra_tags) +} + +resource "datadog_monitor" "status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub is down" + message = coalesce(var.status_message, var.message) + type = "query alert" + + query = < ${var.failed_c2d_methods_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.failed_c2d_methods_rate_threshold_warning + critical = var.failed_c2d_methods_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.failed_c2d_methods_rate_extra_tags) +} + +resource "datadog_monitor" "too_many_c2d_twin_read_failed" { + count = var.failed_c2d_twin_read_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub Too many c2d twin read failure {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.failed_c2d_twin_read_rate_message, var.message) + type = "query alert" + + query = < ${var.failed_c2d_twin_read_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.failed_c2d_twin_read_rate_threshold_warning + critical = var.failed_c2d_twin_read_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.failed_c2d_twin_read_rate_extra_tags) +} + +resource "datadog_monitor" "too_many_c2d_twin_update_failed" { + count = var.failed_c2d_twin_update_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub Too many c2d twin update failure {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.failed_c2d_twin_update_rate_message, var.message) + type = "query alert" + + query = < ${var.failed_c2d_twin_update_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.failed_c2d_twin_update_rate_threshold_warning + critical = var.failed_c2d_twin_update_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.failed_c2d_twin_update_rate_extra_tags) +} + +resource "datadog_monitor" "too_many_d2c_twin_read_failed" { + count = var.failed_d2c_twin_read_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub Too many d2c twin read failure {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.failed_d2c_twin_read_rate_message, var.message) + type = "query alert" + + query = < ${var.failed_d2c_twin_read_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.failed_d2c_twin_read_rate_threshold_warning + critical = var.failed_d2c_twin_read_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.failed_d2c_twin_read_rate_extra_tags) +} + +resource "datadog_monitor" "too_many_d2c_twin_update_failed" { + count = var.failed_d2c_twin_update_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub Too many d2c twin update failure {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.failed_d2c_twin_update_rate_message, var.message) + type = "query alert" + + query = < ${var.failed_d2c_twin_update_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.failed_d2c_twin_update_rate_threshold_warning + critical = var.failed_d2c_twin_update_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.failed_d2c_twin_update_rate_extra_tags) +} + +resource "datadog_monitor" "too_many_d2c_telemetry_egress_dropped" { + count = var.dropped_d2c_telemetry_egress_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub Too many d2c telemetry egress dropped {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.dropped_d2c_telemetry_egress_message, var.message) + type = "query alert" + + query = < ${var.dropped_d2c_telemetry_egress_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.dropped_d2c_telemetry_egress_rate_threshold_warning + critical = var.dropped_d2c_telemetry_egress_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.dropped_d2c_telemetry_egress_extra_tags) +} + +resource "datadog_monitor" "too_many_d2c_telemetry_egress_orphaned" { + count = var.orphaned_d2c_telemetry_egress_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub Too many d2c telemetry egress orphaned {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.orphaned_d2c_telemetry_egress_message, var.message) + type = "query alert" + + query = < ${var.orphaned_d2c_telemetry_egress_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.orphaned_d2c_telemetry_egress_rate_threshold_warning + critical = var.orphaned_d2c_telemetry_egress_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.orphaned_d2c_telemetry_egress_extra_tags) +} + +resource "datadog_monitor" "too_many_d2c_telemetry_egress_invalid" { + count = var.invalid_d2c_telemetry_egress_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub Too many d2c telemetry egress invalid {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.invalid_d2c_telemetry_egress_message, var.message) + type = "query alert" + + query = < ${var.invalid_d2c_telemetry_egress_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.invalid_d2c_telemetry_egress_rate_threshold_warning + critical = var.invalid_d2c_telemetry_egress_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.invalid_d2c_telemetry_egress_extra_tags) +} + +resource "datadog_monitor" "too_many_d2c_telemetry_ingress_nosent" { + count = var.too_many_d2c_telemetry_ingress_nosent_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] IOT Hub Too many d2c telemetry ingress not sent {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.too_many_d2c_telemetry_ingress_nosent_message, var.message) + type = "query alert" + + #For this monitor, the avg is needed to smooth the -1 and +1 that we meet regularly. With just a tiny diff like -1 / + 1, if we put 0.3 it should not ring anymore. But there is a bigger difference (exemple 20) The average will be strongly raised and an alert will be triggered. + query = < ${var.too_many_d2c_telemetry_ingress_nosent_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.too_many_d2c_telemetry_ingress_nosent_rate_threshold_warning + critical = var.too_many_d2c_telemetry_ingress_nosent_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:iothubs", "team:claranet", "created-by:terraform"], var.too_many_d2c_telemetry_ingress_nosent_extra_tags) +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/iothubs/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/iothubs/outputs.tf new file mode 100755 index 0000000..31dd33d --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/iothubs/outputs.tf @@ -0,0 +1,70 @@ +output "status_id" { + description = "id for monitor status" + value = datadog_monitor.status.*.id +} + +output "too_many_c2d_methods_failed_id" { + description = "id for monitor too_many_c2d_methods_failed" + value = datadog_monitor.too_many_c2d_methods_failed.*.id +} + +output "too_many_c2d_twin_read_failed_id" { + description = "id for monitor too_many_c2d_twin_read_failed" + value = datadog_monitor.too_many_c2d_twin_read_failed.*.id +} + +output "too_many_c2d_twin_update_failed_id" { + description = "id for monitor too_many_c2d_twin_update_failed" + value = datadog_monitor.too_many_c2d_twin_update_failed.*.id +} + +output "too_many_d2c_telemetry_egress_dropped_id" { + description = "id for monitor too_many_d2c_telemetry_egress_dropped" + value = datadog_monitor.too_many_d2c_telemetry_egress_dropped.*.id +} + +output "too_many_d2c_telemetry_egress_invalid_id" { + description = "id for monitor too_many_d2c_telemetry_egress_invalid" + value = datadog_monitor.too_many_d2c_telemetry_egress_invalid.*.id +} + +output "too_many_d2c_telemetry_egress_orphaned_id" { + description = "id for monitor too_many_d2c_telemetry_egress_orphaned" + value = datadog_monitor.too_many_d2c_telemetry_egress_orphaned.*.id +} + +output "too_many_d2c_telemetry_ingress_nosent_id" { + description = "id for monitor too_many_d2c_telemetry_ingress_nosent" + value = datadog_monitor.too_many_d2c_telemetry_ingress_nosent.*.id +} + +output "too_many_d2c_twin_read_failed_id" { + description = "id for monitor too_many_d2c_twin_read_failed" + value = datadog_monitor.too_many_d2c_twin_read_failed.*.id +} + +output "too_many_d2c_twin_update_failed_id" { + description = "id for monitor too_many_d2c_twin_update_failed" + value = datadog_monitor.too_many_d2c_twin_update_failed.*.id +} + +output "too_many_jobs_failed_id" { + description = "id for monitor too_many_jobs_failed" + value = datadog_monitor.too_many_jobs_failed.*.id +} + +output "too_many_list_jobs_failed_id" { + description = "id for monitor too_many_list_jobs_failed" + value = datadog_monitor.too_many_list_jobs_failed.*.id +} + +output "too_many_query_jobs_failed_id" { + description = "id for monitor too_many_query_jobs_failed" + value = datadog_monitor.too_many_query_jobs_failed.*.id +} + +output "total_devices_id" { + description = "id for monitor total_devices" + value = datadog_monitor.total_devices.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/iothubs/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/iothubs/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/iothubs/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/keyvault/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/keyvault/README.md new file mode 100755 index 0000000..e74f597 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/keyvault/README.md @@ -0,0 +1,99 @@ +# CLOUD AZURE KEYVAULT DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-keyvault" { + source = "claranet/monitors/datadog//cloud/azure/keyvault" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Key Vault API latency is high +- Key Vault API result rate is low +- Key Vault is down + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | +| [filter-tags-activity](#module\_filter-tags-activity) | ../../../common/filter-tags | n/a | +| [filter-tags-statuscode](#module\_filter-tags-statuscode) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.keyvault_api_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.keyvault_api_result](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.keyvault_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [api\_latency\_enabled](#input\_api\_latency\_enabled) | Flag to enable Key Vault API latency monitor | `string` | `"true"` | no | +| [api\_latency\_extra\_tags](#input\_api\_latency\_extra\_tags) | Extra tags for Key Vault API latency monitor | `list(string)` | `[]` | no | +| [api\_latency\_message](#input\_api\_latency\_message) | Custom message for Key Vault API latency monitor | `string` | `""` | no | +| [api\_latency\_threshold\_critical](#input\_api\_latency\_threshold\_critical) | Critical threshold for Key Vault API latency rate | `number` | `100` | no | +| [api\_latency\_threshold\_warning](#input\_api\_latency\_threshold\_warning) | Warning threshold for Key Vault API latency rate | `number` | `80` | no | +| [api\_latency\_time\_aggregator](#input\_api\_latency\_time\_aggregator) | Monitor aggregator for Key Vault API latency [available values: min, max or avg] | `string` | `"min"` | no | +| [api\_latency\_timeframe](#input\_api\_latency\_timeframe) | Monitor timeframe for Key Vault API latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [api\_result\_enabled](#input\_api\_result\_enabled) | Flag to enable Key Vault API result monitor | `string` | `"true"` | no | +| [api\_result\_extra\_tags](#input\_api\_result\_extra\_tags) | Extra tags for Key Vault API result monitor | `list(string)` | `[]` | no | +| [api\_result\_message](#input\_api\_result\_message) | Custom message for Key Vault API result monitor | `string` | `""` | no | +| [api\_result\_threshold\_critical](#input\_api\_result\_threshold\_critical) | Critical threshold for Key Vault API result rate | `number` | `10` | no | +| [api\_result\_threshold\_warning](#input\_api\_result\_threshold\_warning) | Warning threshold for Key Vault API result rate | `number` | `30` | no | +| [api\_result\_time\_aggregator](#input\_api\_result\_time\_aggregator) | Monitor aggregator for Key Vault API result [available values: min, max or avg] | `string` | `"max"` | no | +| [api\_result\_timeframe](#input\_api\_result\_timeframe) | Monitor timeframe for Key Vault API result [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [keyvault\_status\_no\_data\_timeframe](#input\_keyvault\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable Key Vault status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for Key Vault status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for Key Vault status monitor | `string` | `""` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for Key Vault status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for Key Vault status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [keyvault\_api\_latency\_id](#output\_keyvault\_api\_latency\_id) | id for monitor keyvault\_api\_latency | +| [keyvault\_api\_result\_id](#output\_keyvault\_api\_result\_id) | id for monitor keyvault\_api\_result | +| [keyvault\_status\_id](#output\_keyvault\_status\_id) | id for monitor keyvault\_status | +## Related documentation + +DataDog documentation : [https://docs.datadoghq.com/integrations/azure/](https://docs.datadoghq.com/integrations/azure/) +You must search `keyvault`, there is no integration for now. + +Azure metrics documentation : [https://docs.microsoft.com/fr-fr/azure/monitoring-and-diagnostics/monitoring-supported-metrics#microsoftkeyvaultvaults](https://docs.microsoft.com/fr-fr/azure/monitoring-and-diagnostics/monitoring-supported-metrics#microsoftkeyvaultvaults) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/keyvault/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/keyvault/inputs.tf new file mode 100755 index 0000000..177752c --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/keyvault/inputs.tf @@ -0,0 +1,158 @@ +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "keyvault_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# Azure Key Vault specific variables +variable "status_enabled" { + description = "Flag to enable Key Vault status monitor" + type = string + default = "true" +} + +variable "status_message" { + description = "Custom message for Key Vault status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for Key Vault status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for Key Vault status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + default = "last_5m" +} + +variable "status_extra_tags" { + description = "Extra tags for Key Vault status monitor" + type = list(string) + default = [] +} + +variable "api_result_enabled" { + description = "Flag to enable Key Vault API result monitor" + type = string + default = "true" +} + +variable "api_result_message" { + description = "Custom message for Key Vault API result monitor" + type = string + default = "" +} + +variable "api_result_time_aggregator" { + description = "Monitor aggregator for Key Vault API result [available values: min, max or avg]" + type = string + default = "max" +} + +variable "api_result_timeframe" { + description = "Monitor timeframe for Key Vault API result [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + default = "last_5m" +} + +variable "api_result_threshold_critical" { + description = "Critical threshold for Key Vault API result rate" + default = 10 +} + +variable "api_result_threshold_warning" { + description = "Warning threshold for Key Vault API result rate" + default = 30 +} + +variable "api_result_extra_tags" { + description = "Extra tags for Key Vault API result monitor" + type = list(string) + default = [] +} + +variable "api_latency_enabled" { + description = "Flag to enable Key Vault API latency monitor" + type = string + default = "true" +} + +variable "api_latency_message" { + description = "Custom message for Key Vault API latency monitor" + type = string + default = "" +} + +variable "api_latency_time_aggregator" { + description = "Monitor aggregator for Key Vault API latency [available values: min, max or avg]" + type = string + default = "min" +} + +variable "api_latency_timeframe" { + description = "Monitor timeframe for Key Vault API latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + default = "last_5m" +} + +variable "api_latency_threshold_critical" { + description = "Critical threshold for Key Vault API latency rate" + default = 100 +} + +variable "api_latency_threshold_warning" { + description = "Warning threshold for Key Vault API latency rate" + default = 80 +} + +variable "api_latency_extra_tags" { + description = "Extra tags for Key Vault API latency monitor" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/keyvault/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/keyvault/modules.tf new file mode 100755 index 0000000..9fd2ab3 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/keyvault/modules.tf @@ -0,0 +1,32 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_keyvault" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + +module "filter-tags-statuscode" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_keyvault" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["statuscode:%s"] +} + +module "filter-tags-activity" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_keyvault" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags_excluded = ["activityname:secretlist"] +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/keyvault/monitors-keyvault.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/keyvault/monitors-keyvault.tf new file mode 100755 index 0000000..85fb14b --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/keyvault/monitors-keyvault.tf @@ -0,0 +1,89 @@ +resource "datadog_monitor" "keyvault_status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Key Vault is down" + message = coalesce(var.status_message, var.message) + type = "query alert" + + query = < ${var.api_latency_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.api_latency_threshold_critical + warning = var.api_latency_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:keyvault", "team:claranet", "created-by:terraform"], var.api_latency_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/keyvault/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/keyvault/outputs.tf new file mode 100755 index 0000000..8f67e0b --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/keyvault/outputs.tf @@ -0,0 +1,15 @@ +output "keyvault_api_latency_id" { + description = "id for monitor keyvault_api_latency" + value = datadog_monitor.keyvault_api_latency.*.id +} + +output "keyvault_api_result_id" { + description = "id for monitor keyvault_api_result" + value = datadog_monitor.keyvault_api_result.*.id +} + +output "keyvault_status_id" { + description = "id for monitor keyvault_status" + value = datadog_monitor.keyvault_status.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/keyvault/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/keyvault/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/keyvault/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/load-balancer/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/load-balancer/README.md new file mode 100755 index 0000000..d4c337e --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/load-balancer/README.md @@ -0,0 +1,74 @@ +# CLOUD AZURE LOAD-BALANCER DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-load-balancer" { + source = "claranet/monitors/datadog//cloud/azure/load-balancer" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Load Balancer is unreachable + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.loadbalancer_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [loadbalancer\_status\_no\_data\_timeframe](#input\_loadbalancer\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable Load Balancer status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for Load Balancer status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for Load Balancer status monitor | `string` | `""` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for Load Balancer status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for Load Balancer status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [loadbalancer\_status\_id](#output\_loadbalancer\_status\_id) | id for monitor loadbalancer\_status | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure/?tab=azurecliv20](https://docs.datadoghq.com/integrations/azure/?tab=azurecliv20) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/load-balancer/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/load-balancer/inputs.tf new file mode 100755 index 0000000..614411f --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/load-balancer/inputs.tf @@ -0,0 +1,80 @@ +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "loadbalancer_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# Azure Load Balancer specific variables +variable "status_enabled" { + description = "Flag to enable Load Balancer status monitor" + type = string + default = "true" +} + +variable "status_message" { + description = "Custom message for Load Balancer status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for Load Balancer status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for Load Balancer status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + default = "last_5m" +} + +variable "status_extra_tags" { + description = "Extra tags for Load Balancer status monitor" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/load-balancer/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/load-balancer/modules.tf new file mode 100755 index 0000000..d68393b --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/load-balancer/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_load-balancer" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/load-balancer/monitors-load-balancer.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/load-balancer/monitors-load-balancer.tf new file mode 100755 index 0000000..3ffdf53 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/load-balancer/monitors-load-balancer.tf @@ -0,0 +1,26 @@ +resource "datadog_monitor" "loadbalancer_status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Load Balancer is unreachable" + message = coalesce(var.status_message, var.message) + type = "query alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.mysql_cpu_usage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_free_storage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_io_consumption](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_memory_usage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_usage\_enabled](#input\_cpu\_usage\_enabled) | Flag to enable Mysql status monitor | `string` | `"true"` | no | +| [cpu\_usage\_extra\_tags](#input\_cpu\_usage\_extra\_tags) | Extra tags for Mysql status monitor | `list(string)` | `[]` | no | +| [cpu\_usage\_message](#input\_cpu\_usage\_message) | Custom message for Mysql CPU monitor | `string` | `""` | no | +| [cpu\_usage\_threshold\_critical](#input\_cpu\_usage\_threshold\_critical) | Mysql CPU usage in percent (critical threshold) | `string` | `"90"` | no | +| [cpu\_usage\_threshold\_warning](#input\_cpu\_usage\_threshold\_warning) | Mysql CPU usage in percent (warning threshold) | `string` | `"80"` | no | +| [cpu\_usage\_time\_aggregator](#input\_cpu\_usage\_time\_aggregator) | Monitor aggregator for Mysql CPU [available values: min, max or avg] | `string` | `"min"` | no | +| [cpu\_usage\_timeframe](#input\_cpu\_usage\_timeframe) | Monitor timeframe for Mysql CPU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [free\_storage\_enabled](#input\_free\_storage\_enabled) | Flag to enable Mysql status monitor | `string` | `"true"` | no | +| [free\_storage\_extra\_tags](#input\_free\_storage\_extra\_tags) | Extra tags for Mysql status monitor | `list(string)` | `[]` | no | +| [free\_storage\_message](#input\_free\_storage\_message) | Custom message for Mysql Free Storage monitor | `string` | `""` | no | +| [free\_storage\_threshold\_critical](#input\_free\_storage\_threshold\_critical) | Mysql Free Storage remaining in percent (critical threshold) | `string` | `"10"` | no | +| [free\_storage\_threshold\_warning](#input\_free\_storage\_threshold\_warning) | Mysql Free Storage remaining in percent (warning threshold) | `string` | `"20"` | no | +| [free\_storage\_time\_aggregator](#input\_free\_storage\_time\_aggregator) | Monitor aggregator for Mysql Free Storage [available values: min, max or avg] | `string` | `"min"` | no | +| [free\_storage\_timeframe](#input\_free\_storage\_timeframe) | Monitor timeframe for Mysql Free Storage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [io\_consumption\_enabled](#input\_io\_consumption\_enabled) | Flag to enable Mysql status monitor | `string` | `"true"` | no | +| [io\_consumption\_extra\_tags](#input\_io\_consumption\_extra\_tags) | Extra tags for Mysql status monitor | `list(string)` | `[]` | no | +| [io\_consumption\_message](#input\_io\_consumption\_message) | Custom message for Mysql IO consumption monitor | `string` | `""` | no | +| [io\_consumption\_threshold\_critical](#input\_io\_consumption\_threshold\_critical) | Mysql IO consumption in percent (critical threshold) | `string` | `"90"` | no | +| [io\_consumption\_threshold\_warning](#input\_io\_consumption\_threshold\_warning) | Mysql IO consumption in percent (warning threshold) | `string` | `"80"` | no | +| [io\_consumption\_time\_aggregator](#input\_io\_consumption\_time\_aggregator) | Monitor aggregator for Mysql IO consumption [available values: min, max or avg] | `string` | `"min"` | no | +| [io\_consumption\_timeframe](#input\_io\_consumption\_timeframe) | Monitor timeframe for Mysql IO consumption [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [memory\_usage\_enabled](#input\_memory\_usage\_enabled) | Flag to enable Mysql status monitor | `string` | `"true"` | no | +| [memory\_usage\_extra\_tags](#input\_memory\_usage\_extra\_tags) | Extra tags for Mysql status monitor | `list(string)` | `[]` | no | +| [memory\_usage\_message](#input\_memory\_usage\_message) | Custom message for Mysql memory monitor | `string` | `""` | no | +| [memory\_usage\_threshold\_critical](#input\_memory\_usage\_threshold\_critical) | Mysql memory usage in percent (critical threshold) | `string` | `"90"` | no | +| [memory\_usage\_threshold\_warning](#input\_memory\_usage\_threshold\_warning) | Mysql memory usage in percent (warning threshold) | `string` | `"80"` | no | +| [memory\_usage\_time\_aggregator](#input\_memory\_usage\_time\_aggregator) | Monitor aggregator for Mysql memory [available values: min, max or avg] | `string` | `"min"` | no | +| [memory\_usage\_timeframe](#input\_memory\_usage\_timeframe) | Monitor timeframe for Mysql memory [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [mysql\_cpu\_usage\_id](#output\_mysql\_cpu\_usage\_id) | id for monitor mysql\_cpu\_usage | +| [mysql\_free\_storage\_id](#output\_mysql\_free\_storage\_id) | id for monitor mysql\_free\_storage | +| [mysql\_io\_consumption\_id](#output\_mysql\_io\_consumption\_id) | id for monitor mysql\_io\_consumption | +| [mysql\_memory\_usage\_id](#output\_mysql\_memory\_usage\_id) | id for monitor mysql\_memory\_usage | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure/](https://docs.datadoghq.com/integrations/azure/) +You have to search `mysql` + +Azure Database for MySQL servers metrics documentation: [https://docs.microsoft.com/en-us/azure/mysql/concepts-monitoring](https://docs.microsoft.com/en-us/azure/mysql/concepts-monitoring) + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/mysql/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/mysql/inputs.tf new file mode 100755 index 0000000..681cc49 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/mysql/inputs.tf @@ -0,0 +1,203 @@ +# Global Terraform +variable "environment" { + description = "Architecture environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +# Azure Databases for MySQL Servers specific variables + +variable "cpu_usage_enabled" { + description = "Flag to enable Mysql status monitor" + type = string + default = "true" +} + +variable "cpu_usage_extra_tags" { + description = "Extra tags for Mysql status monitor" + type = list(string) + default = [] +} + +variable "cpu_usage_message" { + description = "Custom message for Mysql CPU monitor" + type = string + default = "" +} + +variable "cpu_usage_time_aggregator" { + description = "Monitor aggregator for Mysql CPU [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cpu_usage_timeframe" { + description = "Monitor timeframe for Mysql CPU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "cpu_usage_threshold_warning" { + description = "Mysql CPU usage in percent (warning threshold)" + default = "80" +} + +variable "cpu_usage_threshold_critical" { + description = "Mysql CPU usage in percent (critical threshold)" + default = "90" +} + +variable "free_storage_enabled" { + description = "Flag to enable Mysql status monitor" + type = string + default = "true" +} + +variable "free_storage_extra_tags" { + description = "Extra tags for Mysql status monitor" + type = list(string) + default = [] +} + +variable "free_storage_message" { + description = "Custom message for Mysql Free Storage monitor" + type = string + default = "" +} + +variable "free_storage_time_aggregator" { + description = "Monitor aggregator for Mysql Free Storage [available values: min, max or avg]" + type = string + default = "min" +} + +variable "free_storage_timeframe" { + description = "Monitor timeframe for Mysql Free Storage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "free_storage_threshold_warning" { + description = "Mysql Free Storage remaining in percent (warning threshold)" + default = "20" +} + +variable "free_storage_threshold_critical" { + description = "Mysql Free Storage remaining in percent (critical threshold)" + default = "10" +} + +variable "io_consumption_enabled" { + description = "Flag to enable Mysql status monitor" + type = string + default = "true" +} + +variable "io_consumption_extra_tags" { + description = "Extra tags for Mysql status monitor" + type = list(string) + default = [] +} + +variable "io_consumption_message" { + description = "Custom message for Mysql IO consumption monitor" + type = string + default = "" +} + +variable "io_consumption_time_aggregator" { + description = "Monitor aggregator for Mysql IO consumption [available values: min, max or avg]" + type = string + default = "min" +} + +variable "io_consumption_timeframe" { + description = "Monitor timeframe for Mysql IO consumption [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "io_consumption_threshold_warning" { + description = "Mysql IO consumption in percent (warning threshold)" + default = "80" +} + +variable "io_consumption_threshold_critical" { + description = "Mysql IO consumption in percent (critical threshold)" + default = "90" +} + +variable "memory_usage_enabled" { + description = "Flag to enable Mysql status monitor" + type = string + default = "true" +} + +variable "memory_usage_extra_tags" { + description = "Extra tags for Mysql status monitor" + type = list(string) + default = [] +} + +variable "memory_usage_message" { + description = "Custom message for Mysql memory monitor" + type = string + default = "" +} + +variable "memory_usage_time_aggregator" { + description = "Monitor aggregator for Mysql memory [available values: min, max or avg]" + type = string + default = "min" +} + +variable "memory_usage_timeframe" { + description = "Monitor timeframe for Mysql memory [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "memory_usage_threshold_warning" { + description = "Mysql memory usage in percent (warning threshold)" + default = "80" +} + +variable "memory_usage_threshold_critical" { + description = "Mysql memory usage in percent (critical threshold)" + default = "90" +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/mysql/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/mysql/modules.tf new file mode 100755 index 0000000..87489ca --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/mysql/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_mysql" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/mysql/monitors-mysql.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/mysql/monitors-mysql.tf new file mode 100755 index 0000000..6e24841 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/mysql/monitors-mysql.tf @@ -0,0 +1,120 @@ +resource "datadog_monitor" "mysql_cpu_usage" { + count = var.cpu_usage_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql Server CPU usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cpu_usage_message, var.message) + type = "query alert" + + query = < ${var.cpu_usage_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.cpu_usage_threshold_critical + warning = var.cpu_usage_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:mysql", "team:claranet", "created-by:terraform"], var.cpu_usage_extra_tags) +} + +resource "datadog_monitor" "mysql_free_storage" { + count = var.free_storage_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql Server storage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.free_storage_message, var.message) + type = "query alert" + + query = < ${var.io_consumption_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.io_consumption_threshold_critical + warning = var.io_consumption_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:mysql", "team:claranet", "created-by:terraform"], var.io_consumption_extra_tags) +} + +resource "datadog_monitor" "mysql_memory_usage" { + count = var.memory_usage_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql Server memory usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.memory_usage_message, var.message) + type = "query alert" + + query = < ${var.memory_usage_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.memory_usage_threshold_critical + warning = var.memory_usage_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:mysql", "team:claranet", "created-by:terraform"], var.memory_usage_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/mysql/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/mysql/outputs.tf new file mode 100755 index 0000000..ace5b8a --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/mysql/outputs.tf @@ -0,0 +1,20 @@ +output "mysql_cpu_usage_id" { + description = "id for monitor mysql_cpu_usage" + value = datadog_monitor.mysql_cpu_usage.*.id +} + +output "mysql_free_storage_id" { + description = "id for monitor mysql_free_storage" + value = datadog_monitor.mysql_free_storage.*.id +} + +output "mysql_io_consumption_id" { + description = "id for monitor mysql_io_consumption" + value = datadog_monitor.mysql_io_consumption.*.id +} + +output "mysql_memory_usage_id" { + description = "id for monitor mysql_memory_usage" + value = datadog_monitor.mysql_memory_usage.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/mysql/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/mysql/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/mysql/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/postgresql/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/postgresql/README.md new file mode 100755 index 0000000..4e1121c --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/postgresql/README.md @@ -0,0 +1,114 @@ +# CLOUD AZURE POSTGRESQL DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-postgresql" { + source = "claranet/monitors/datadog//cloud/azure/postgresql" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Postgresql Server CPU usage +- Postgresql Server has no connection +- Postgresql Server IO consumption +- Postgresql Server memory usage +- Postgresql Server storage + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.postgresql_cpu_usage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.postgresql_free_storage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.postgresql_io_consumption](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.postgresql_memory_usage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.postgresql_no_connection](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_usage\_enabled](#input\_cpu\_usage\_enabled) | Flag to enable PostgreSQL status monitor | `string` | `"true"` | no | +| [cpu\_usage\_extra\_tags](#input\_cpu\_usage\_extra\_tags) | Extra tags for PostgreSQL status monitor | `list(string)` | `[]` | no | +| [cpu\_usage\_message](#input\_cpu\_usage\_message) | Custom message for PostgreSQL CPU monitor | `string` | `""` | no | +| [cpu\_usage\_threshold\_critical](#input\_cpu\_usage\_threshold\_critical) | PostgreSQL CPU usage in percent (critical threshold) | `string` | `"90"` | no | +| [cpu\_usage\_threshold\_warning](#input\_cpu\_usage\_threshold\_warning) | PostgreSQL CPU usage in percent (warning threshold) | `string` | `"80"` | no | +| [cpu\_usage\_time\_aggregator](#input\_cpu\_usage\_time\_aggregator) | Monitor aggregator for PostgreSQL CPU [available values: min, max or avg] | `string` | `"min"` | no | +| [cpu\_usage\_timeframe](#input\_cpu\_usage\_timeframe) | Monitor timeframe for PostgreSQL CPU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [free\_storage\_enabled](#input\_free\_storage\_enabled) | Flag to enable PostgreSQL status monitor | `string` | `"true"` | no | +| [free\_storage\_extra\_tags](#input\_free\_storage\_extra\_tags) | Extra tags for PostgreSQL status monitor | `list(string)` | `[]` | no | +| [free\_storage\_message](#input\_free\_storage\_message) | Custom message for PostgreSQL Free Storage monitor | `string` | `""` | no | +| [free\_storage\_threshold\_critical](#input\_free\_storage\_threshold\_critical) | PostgreSQL Free Storage remaining in percent (critical threshold) | `string` | `"10"` | no | +| [free\_storage\_threshold\_warning](#input\_free\_storage\_threshold\_warning) | PostgreSQL Free Storage remaining in percent (warning threshold) | `string` | `"20"` | no | +| [free\_storage\_time\_aggregator](#input\_free\_storage\_time\_aggregator) | Monitor aggregator for PostgreSQL Free Storage [available values: min, max or avg] | `string` | `"min"` | no | +| [free\_storage\_timeframe](#input\_free\_storage\_timeframe) | Monitor timeframe for PostgreSQL Free Storage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [io\_consumption\_enabled](#input\_io\_consumption\_enabled) | Flag to enable PostgreSQL status monitor | `string` | `"true"` | no | +| [io\_consumption\_extra\_tags](#input\_io\_consumption\_extra\_tags) | Extra tags for PostgreSQL status monitor | `list(string)` | `[]` | no | +| [io\_consumption\_message](#input\_io\_consumption\_message) | Custom message for PostgreSQL IO consumption monitor | `string` | `""` | no | +| [io\_consumption\_threshold\_critical](#input\_io\_consumption\_threshold\_critical) | PostgreSQL IO consumption in percent (critical threshold) | `string` | `"90"` | no | +| [io\_consumption\_threshold\_warning](#input\_io\_consumption\_threshold\_warning) | PostgreSQL IO consumption in percent (warning threshold) | `string` | `"80"` | no | +| [io\_consumption\_time\_aggregator](#input\_io\_consumption\_time\_aggregator) | Monitor aggregator for PostgreSQL IO consumption [available values: min, max or avg] | `string` | `"min"` | no | +| [io\_consumption\_timeframe](#input\_io\_consumption\_timeframe) | Monitor timeframe for PostgreSQL IO consumption [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [memory\_usage\_enabled](#input\_memory\_usage\_enabled) | Flag to enable PostgreSQL status monitor | `string` | `"true"` | no | +| [memory\_usage\_extra\_tags](#input\_memory\_usage\_extra\_tags) | Extra tags for PostgreSQL status monitor | `list(string)` | `[]` | no | +| [memory\_usage\_message](#input\_memory\_usage\_message) | Custom message for PostgreSQL memory monitor | `string` | `""` | no | +| [memory\_usage\_threshold\_critical](#input\_memory\_usage\_threshold\_critical) | PostgreSQL memory usage in percent (critical threshold) | `string` | `"90"` | no | +| [memory\_usage\_threshold\_warning](#input\_memory\_usage\_threshold\_warning) | PostgreSQL memory usage in percent (warning threshold) | `string` | `"80"` | no | +| [memory\_usage\_time\_aggregator](#input\_memory\_usage\_time\_aggregator) | Monitor aggregator for PostgreSQL memory [available values: min, max or avg] | `string` | `"min"` | no | +| [memory\_usage\_timeframe](#input\_memory\_usage\_timeframe) | Monitor timeframe for PostgreSQL memory [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [no\_connection\_enabled](#input\_no\_connection\_enabled) | Flag to enable PostgreSQL status monitor | `string` | `"true"` | no | +| [no\_connection\_extra\_tags](#input\_no\_connection\_extra\_tags) | Extra tags for PostgreSQL status monitor | `list(string)` | `[]` | no | +| [no\_connection\_message](#input\_no\_connection\_message) | Custom message for PostgreSQL no connection monitor | `string` | `""` | no | +| [no\_connection\_time\_aggregator](#input\_no\_connection\_time\_aggregator) | Monitor aggregator for PostgreSQL no connection [available values: min, max or avg] | `string` | `"min"` | no | +| [no\_connection\_timeframe](#input\_no\_connection\_timeframe) | Monitor timeframe for PostgreSQL no connection [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [postgresql\_no\_connection\_no\_data\_timeframe](#input\_postgresql\_no\_connection\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [postgresql\_cpu\_usage\_id](#output\_postgresql\_cpu\_usage\_id) | id for monitor postgresql\_cpu\_usage | +| [postgresql\_free\_storage\_id](#output\_postgresql\_free\_storage\_id) | id for monitor postgresql\_free\_storage | +| [postgresql\_io\_consumption\_id](#output\_postgresql\_io\_consumption\_id) | id for monitor postgresql\_io\_consumption | +| [postgresql\_memory\_usage\_id](#output\_postgresql\_memory\_usage\_id) | id for monitor postgresql\_memory\_usage | +| [postgresql\_no\_connection\_id](#output\_postgresql\_no\_connection\_id) | id for monitor postgresql\_no\_connection | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure/](https://docs.datadoghq.com/integrations/azure/) +You have to search `mysql` diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/postgresql/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/postgresql/inputs.tf new file mode 100755 index 0000000..07512a0 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/postgresql/inputs.tf @@ -0,0 +1,239 @@ +# Global Terraform +variable "environment" { + description = "Architecture environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "postgresql_no_connection_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +# Azure Databases for PostgreSQL Servers specific variables + +variable "cpu_usage_enabled" { + description = "Flag to enable PostgreSQL status monitor" + type = string + default = "true" +} + +variable "cpu_usage_extra_tags" { + description = "Extra tags for PostgreSQL status monitor" + type = list(string) + default = [] +} + +variable "cpu_usage_message" { + description = "Custom message for PostgreSQL CPU monitor" + type = string + default = "" +} + +variable "cpu_usage_time_aggregator" { + description = "Monitor aggregator for PostgreSQL CPU [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cpu_usage_timeframe" { + description = "Monitor timeframe for PostgreSQL CPU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "cpu_usage_threshold_warning" { + description = "PostgreSQL CPU usage in percent (warning threshold)" + default = "80" +} + +variable "cpu_usage_threshold_critical" { + description = "PostgreSQL CPU usage in percent (critical threshold)" + default = "90" +} + +variable "no_connection_enabled" { + description = "Flag to enable PostgreSQL status monitor" + type = string + default = "true" +} + +variable "no_connection_extra_tags" { + description = "Extra tags for PostgreSQL status monitor" + type = list(string) + default = [] +} + +variable "no_connection_message" { + description = "Custom message for PostgreSQL no connection monitor" + type = string + default = "" +} + +variable "no_connection_time_aggregator" { + description = "Monitor aggregator for PostgreSQL no connection [available values: min, max or avg]" + type = string + default = "min" +} + +variable "no_connection_timeframe" { + description = "Monitor timeframe for PostgreSQL no connection [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "free_storage_enabled" { + description = "Flag to enable PostgreSQL status monitor" + type = string + default = "true" +} + +variable "free_storage_extra_tags" { + description = "Extra tags for PostgreSQL status monitor" + type = list(string) + default = [] +} + +variable "free_storage_message" { + description = "Custom message for PostgreSQL Free Storage monitor" + type = string + default = "" +} + +variable "free_storage_time_aggregator" { + description = "Monitor aggregator for PostgreSQL Free Storage [available values: min, max or avg]" + type = string + default = "min" +} + +variable "free_storage_timeframe" { + description = "Monitor timeframe for PostgreSQL Free Storage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "free_storage_threshold_warning" { + description = "PostgreSQL Free Storage remaining in percent (warning threshold)" + default = "20" +} + +variable "free_storage_threshold_critical" { + description = "PostgreSQL Free Storage remaining in percent (critical threshold)" + default = "10" +} + +variable "io_consumption_enabled" { + description = "Flag to enable PostgreSQL status monitor" + type = string + default = "true" +} + +variable "io_consumption_extra_tags" { + description = "Extra tags for PostgreSQL status monitor" + type = list(string) + default = [] +} + +variable "io_consumption_message" { + description = "Custom message for PostgreSQL IO consumption monitor" + type = string + default = "" +} + +variable "io_consumption_time_aggregator" { + description = "Monitor aggregator for PostgreSQL IO consumption [available values: min, max or avg]" + type = string + default = "min" +} + +variable "io_consumption_timeframe" { + description = "Monitor timeframe for PostgreSQL IO consumption [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "io_consumption_threshold_warning" { + description = "PostgreSQL IO consumption in percent (warning threshold)" + default = "80" +} + +variable "io_consumption_threshold_critical" { + description = "PostgreSQL IO consumption in percent (critical threshold)" + default = "90" +} + +variable "memory_usage_enabled" { + description = "Flag to enable PostgreSQL status monitor" + type = string + default = "true" +} + +variable "memory_usage_extra_tags" { + description = "Extra tags for PostgreSQL status monitor" + type = list(string) + default = [] +} + +variable "memory_usage_message" { + description = "Custom message for PostgreSQL memory monitor" + type = string + default = "" +} + +variable "memory_usage_time_aggregator" { + description = "Monitor aggregator for PostgreSQL memory [available values: min, max or avg]" + type = string + default = "min" +} + +variable "memory_usage_timeframe" { + description = "Monitor timeframe for PostgreSQL memory [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "memory_usage_threshold_warning" { + description = "PostgreSQL memory usage in percent (warning threshold)" + default = "80" +} + +variable "memory_usage_threshold_critical" { + description = "PostgreSQL memory usage in percent (critical threshold)" + default = "90" +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/postgresql/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/postgresql/modules.tf new file mode 100755 index 0000000..52a7f41 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/postgresql/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_postgresql" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/postgresql/monitors-postegresql.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/postgresql/monitors-postegresql.tf new file mode 100755 index 0000000..3e96e23 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/postgresql/monitors-postegresql.tf @@ -0,0 +1,146 @@ +resource "datadog_monitor" "postgresql_cpu_usage" { + count = var.cpu_usage_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Postgresql Server CPU usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cpu_usage_message, var.message) + type = "query alert" + + query = < ${var.cpu_usage_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.cpu_usage_threshold_critical + warning = var.cpu_usage_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:postgresql", "team:claranet", "created-by:terraform"], var.cpu_usage_extra_tags) +} + +resource "datadog_monitor" "postgresql_no_connection" { + count = var.no_connection_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Postgresql Server has no connection" + message = coalesce(var.no_connection_message, var.message) + type = "query alert" + + query = < ${var.io_consumption_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.io_consumption_threshold_critical + warning = var.io_consumption_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:postgresql", "team:claranet", "created-by:terraform"], var.io_consumption_extra_tags) +} + +resource "datadog_monitor" "postgresql_memory_usage" { + count = var.memory_usage_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Postgresql Server memory usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.memory_usage_message, var.message) + type = "query alert" + + query = < ${var.memory_usage_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.memory_usage_threshold_critical + warning = var.memory_usage_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:postgresql", "team:claranet", "created-by:terraform"], var.memory_usage_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/postgresql/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/postgresql/outputs.tf new file mode 100755 index 0000000..43af1ce --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/postgresql/outputs.tf @@ -0,0 +1,25 @@ +output "postgresql_cpu_usage_id" { + description = "id for monitor postgresql_cpu_usage" + value = datadog_monitor.postgresql_cpu_usage.*.id +} + +output "postgresql_free_storage_id" { + description = "id for monitor postgresql_free_storage" + value = datadog_monitor.postgresql_free_storage.*.id +} + +output "postgresql_io_consumption_id" { + description = "id for monitor postgresql_io_consumption" + value = datadog_monitor.postgresql_io_consumption.*.id +} + +output "postgresql_memory_usage_id" { + description = "id for monitor postgresql_memory_usage" + value = datadog_monitor.postgresql_memory_usage.*.id +} + +output "postgresql_no_connection_id" { + description = "id for monitor postgresql_no_connection" + value = datadog_monitor.postgresql_no_connection.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/postgresql/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/postgresql/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/postgresql/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/redis/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/redis/README.md new file mode 100755 index 0000000..01991b1 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/redis/README.md @@ -0,0 +1,106 @@ +# CLOUD AZURE REDIS DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-redis" { + source = "claranet/monitors/datadog//cloud/azure/redis" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Redis {{name}} is down +- Redis processor time too high +- Redis server load too high +- Redis too many evictedkeys + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.evictedkeys](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.percent_processor_time](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.server_load](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [evictedkeys\_limit\_enabled](#input\_evictedkeys\_limit\_enabled) | Flag to enable Redis evicted keys monitor | `string` | `"true"` | no | +| [evictedkeys\_limit\_extra\_tags](#input\_evictedkeys\_limit\_extra\_tags) | Extra tags for Redis evicted keys monitor | `list(string)` | `[]` | no | +| [evictedkeys\_limit\_message](#input\_evictedkeys\_limit\_message) | Custom message for Redis evicted keys monitor | `string` | `""` | no | +| [evictedkeys\_limit\_threshold\_critical](#input\_evictedkeys\_limit\_threshold\_critical) | Evicted keys limit (critical threshold) | `number` | `100` | no | +| [evictedkeys\_limit\_threshold\_warning](#input\_evictedkeys\_limit\_threshold\_warning) | Evicted keys limit (warning threshold) | `number` | `0` | no | +| [evictedkeys\_limit\_time\_aggregator](#input\_evictedkeys\_limit\_time\_aggregator) | Monitor aggregator for Redis evicted keys [available values: min, max or avg] | `string` | `"avg"` | no | +| [evictedkeys\_limit\_timeframe](#input\_evictedkeys\_limit\_timeframe) | Monitor timeframe for Redis evicted keys [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a Redis monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [percent\_processor\_time\_enabled](#input\_percent\_processor\_time\_enabled) | Flag to enable Redis processor monitor | `string` | `"true"` | no | +| [percent\_processor\_time\_extra\_tags](#input\_percent\_processor\_time\_extra\_tags) | Extra tags for Redis processor monitor | `list(string)` | `[]` | no | +| [percent\_processor\_time\_message](#input\_percent\_processor\_time\_message) | Custom message for Redis processor monitor | `string` | `""` | no | +| [percent\_processor\_time\_threshold\_critical](#input\_percent\_processor\_time\_threshold\_critical) | Processor time percent (critical threshold) | `number` | `80` | no | +| [percent\_processor\_time\_threshold\_warning](#input\_percent\_processor\_time\_threshold\_warning) | Processor time percent (warning threshold) | `number` | `60` | no | +| [percent\_processor\_time\_time\_aggregator](#input\_percent\_processor\_time\_time\_aggregator) | Monitor aggregator for Redis processor [available values: min, max or avg] | `string` | `"min"` | no | +| [percent\_processor\_time\_timeframe](#input\_percent\_processor\_time\_timeframe) | Monitor timeframe for Redis processor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [server\_load\_rate\_enabled](#input\_server\_load\_rate\_enabled) | Flag to enable Redis server load monitor | `string` | `"true"` | no | +| [server\_load\_rate\_extra\_tags](#input\_server\_load\_rate\_extra\_tags) | Extra tags for Redis server load monitor | `list(string)` | `[]` | no | +| [server\_load\_rate\_message](#input\_server\_load\_rate\_message) | Custom message for Redis server load monitor | `string` | `""` | no | +| [server\_load\_rate\_threshold\_critical](#input\_server\_load\_rate\_threshold\_critical) | Server CPU load rate (critical threshold) | `number` | `90` | no | +| [server\_load\_rate\_threshold\_warning](#input\_server\_load\_rate\_threshold\_warning) | Server CPU load rate (warning threshold) | `number` | `70` | no | +| [server\_load\_rate\_time\_aggregator](#input\_server\_load\_rate\_time\_aggregator) | Monitor aggregator for Redis server load [available values: min, max or avg] | `string` | `"min"` | no | +| [server\_load\_rate\_timeframe](#input\_server\_load\_rate\_timeframe) | Monitor timeframe for Redis server load [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable Redis status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for Redis status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for Redis status monitor | `string` | `""` | no | +| [status\_no\_data\_timeframe](#input\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for Redis status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for Redis status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [evictedkeys\_id](#output\_evictedkeys\_id) | id for monitor evictedkeys | +| [percent\_processor\_time\_id](#output\_percent\_processor\_time\_id) | id for monitor percent\_processor\_time | +| [server\_load\_id](#output\_server\_load\_id) | id for monitor server\_load | +| [status\_id](#output\_status\_id) | id for monitor status | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure_redis_cache/](https://docs.datadoghq.com/integrations/azure_redis_cache/) + +Azure Redis metrics documentation: [https://docs.microsoft.com/en-us/azure/redis-cache/cache-how-to-monitor](https://docs.microsoft.com/en-us/azure/redis-cache/cache-how-to-monitor) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/redis/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/redis/inputs.tf new file mode 100755 index 0000000..271b2c5 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/redis/inputs.tf @@ -0,0 +1,204 @@ +# Global Terraform +variable "environment" { + description = "Architecture environment" + type = string +} + +# Global DataDog +variable "message" { + description = "Message sent when a Redis monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Azure Redis specific variables + +variable "status_enabled" { + description = "Flag to enable Redis status monitor" + type = string + default = "true" +} + +variable "status_extra_tags" { + description = "Extra tags for Redis status monitor" + type = list(string) + default = [] +} + +variable "status_message" { + description = "Custom message for Redis status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for Redis status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for Redis status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "evictedkeys_limit_enabled" { + description = "Flag to enable Redis evicted keys monitor" + type = string + default = "true" +} + +variable "evictedkeys_limit_extra_tags" { + description = "Extra tags for Redis evicted keys monitor" + type = list(string) + default = [] +} + +variable "evictedkeys_limit_message" { + description = "Custom message for Redis evicted keys monitor" + type = string + default = "" +} + +variable "evictedkeys_limit_time_aggregator" { + description = "Monitor aggregator for Redis evicted keys [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "evictedkeys_limit_timeframe" { + description = "Monitor timeframe for Redis evicted keys [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "evictedkeys_limit_threshold_warning" { + description = "Evicted keys limit (warning threshold)" + default = 0 +} + +variable "evictedkeys_limit_threshold_critical" { + description = "Evicted keys limit (critical threshold)" + default = 100 +} + +variable "percent_processor_time_enabled" { + description = "Flag to enable Redis processor monitor" + type = string + default = "true" +} + +variable "percent_processor_time_extra_tags" { + description = "Extra tags for Redis processor monitor" + type = list(string) + default = [] +} + +variable "percent_processor_time_message" { + description = "Custom message for Redis processor monitor" + type = string + default = "" +} + +variable "percent_processor_time_time_aggregator" { + description = "Monitor aggregator for Redis processor [available values: min, max or avg]" + type = string + default = "min" +} + +variable "percent_processor_time_timeframe" { + description = "Monitor timeframe for Redis processor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "percent_processor_time_threshold_critical" { + description = "Processor time percent (critical threshold)" + default = 80 +} + +variable "percent_processor_time_threshold_warning" { + description = "Processor time percent (warning threshold)" + default = 60 +} + +variable "server_load_rate_enabled" { + description = "Flag to enable Redis server load monitor" + type = string + default = "true" +} + +variable "server_load_rate_extra_tags" { + description = "Extra tags for Redis server load monitor" + type = list(string) + default = [] +} + +variable "server_load_rate_message" { + description = "Custom message for Redis server load monitor" + type = string + default = "" +} + +variable "server_load_rate_time_aggregator" { + description = "Monitor aggregator for Redis server load [available values: min, max or avg]" + type = string + default = "min" +} + +variable "server_load_rate_timeframe" { + description = "Monitor timeframe for Redis server load [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "server_load_rate_threshold_critical" { + description = "Server CPU load rate (critical threshold)" + default = 90 +} + +variable "server_load_rate_threshold_warning" { + description = "Server CPU load rate (warning threshold)" + default = 70 +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/redis/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/redis/modules.tf new file mode 100755 index 0000000..1c038f7 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/redis/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_redis" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/redis/monitors-azure-redis.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/redis/monitors-azure-redis.tf new file mode 100755 index 0000000..bf6c5ea --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/redis/monitors-azure-redis.tf @@ -0,0 +1,116 @@ +resource "datadog_monitor" "status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Redis {{name}} is down" + message = coalesce(var.status_message, var.message) + type = "query alert" + + query = < ${var.evictedkeys_limit_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.evictedkeys_limit_threshold_warning + critical = var.evictedkeys_limit_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:redis", "team:claranet", "created-by:terraform"], var.evictedkeys_limit_extra_tags) +} + +resource "datadog_monitor" "percent_processor_time" { + count = var.percent_processor_time_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Redis processor time too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.percent_processor_time_message, var.message) + type = "query alert" + + query = < ${var.percent_processor_time_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.percent_processor_time_threshold_warning + critical = var.percent_processor_time_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:redis", "team:claranet", "created-by:terraform"], var.percent_processor_time_extra_tags) +} + +resource "datadog_monitor" "server_load" { + count = var.server_load_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Redis server load too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.server_load_rate_message, var.message) + type = "query alert" + + query = < ${var.server_load_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.server_load_rate_threshold_warning + critical = var.server_load_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:redis", "team:claranet", "created-by:terraform"], var.server_load_rate_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/redis/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/redis/outputs.tf new file mode 100755 index 0000000..de308e6 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/redis/outputs.tf @@ -0,0 +1,20 @@ +output "evictedkeys_id" { + description = "id for monitor evictedkeys" + value = datadog_monitor.evictedkeys.*.id +} + +output "percent_processor_time_id" { + description = "id for monitor percent_processor_time" + value = datadog_monitor.percent_processor_time.*.id +} + +output "server_load_id" { + description = "id for monitor server_load" + value = datadog_monitor.server_load.*.id +} + +output "status_id" { + description = "id for monitor status" + value = datadog_monitor.status.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/redis/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/redis/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/redis/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/serverfarms/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/serverfarms/README.md new file mode 100755 index 0000000..0a6db2a --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/serverfarms/README.md @@ -0,0 +1,92 @@ +# CLOUD AZURE SERVERFARMS DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-serverfarms" { + source = "claranet/monitors/datadog//cloud/azure/serverfarms" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Serverfarm CPU percentage is too high +- Serverfarm is down +- Serverfarm memory percentage is too high + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cpu_percentage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.memory_percentage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_percentage\_enabled](#input\_cpu\_percentage\_enabled) | Flag to enable the serverfarms cpu\_percentage monitor | `string` | `"true"` | no | +| [cpu\_percentage\_extra\_tags](#input\_cpu\_percentage\_extra\_tags) | Extra tags for serverfarms cpu\_percentage monitor | `list(string)` | `[]` | no | +| [cpu\_percentage\_message](#input\_cpu\_percentage\_message) | Custom message for serverfarm cpu\_percentage monitor | `string` | `""` | no | +| [cpu\_percentage\_threshold\_critical](#input\_cpu\_percentage\_threshold\_critical) | CPU percentage (critical threshold) | `number` | `95` | no | +| [cpu\_percentage\_threshold\_warning](#input\_cpu\_percentage\_threshold\_warning) | CPU percentage (warning threshold) | `number` | `90` | no | +| [cpu\_percentage\_time\_aggregator](#input\_cpu\_percentage\_time\_aggregator) | Monitor aggregator for serverfarms cpu\_percentage [available values: min, max or avg] | `string` | `"min"` | no | +| [cpu\_percentage\_timeframe](#input\_cpu\_percentage\_timeframe) | Monitor timeframe for serverfarms cpu\_percentage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_10m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [memory\_percentage\_enabled](#input\_memory\_percentage\_enabled) | Flag to enable the serverfarms memory\_percentage monitor | `string` | `"true"` | no | +| [memory\_percentage\_extra\_tags](#input\_memory\_percentage\_extra\_tags) | Extra tags for serverfarms memory\_percentage monitor | `list(string)` | `[]` | no | +| [memory\_percentage\_message](#input\_memory\_percentage\_message) | Custom message for serverfarm memory\_percentage monitor | `string` | `""` | no | +| [memory\_percentage\_threshold\_critical](#input\_memory\_percentage\_threshold\_critical) | Memory percentage (critical threshold) | `number` | `95` | no | +| [memory\_percentage\_threshold\_warning](#input\_memory\_percentage\_threshold\_warning) | Memory percentage (warning threshold) | `number` | `90` | no | +| [memory\_percentage\_time\_aggregator](#input\_memory\_percentage\_time\_aggregator) | Monitor aggregator for serverfarms memory\_percentage [available values: min, max or avg] | `string` | `"min"` | no | +| [memory\_percentage\_timeframe](#input\_memory\_percentage\_timeframe) | Monitor timeframe for serverfarms memory\_percentage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when a serverfarms monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable the serverfarms status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for serverfarms status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for serverfarm status monitor | `string` | `""` | no | +| [status\_no\_data\_timeframe](#input\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for serverfarms status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for serverfarms status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cpu\_percentage\_id](#output\_cpu\_percentage\_id) | id for monitor cpu\_percentage | +| [memory\_percentage\_id](#output\_memory\_percentage\_id) | id for monitor memory\_percentage | +| [status\_id](#output\_status\_id) | id for monitor status | +## Related documentation + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/serverfarms/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/serverfarms/inputs.tf new file mode 100755 index 0000000..5125827 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/serverfarms/inputs.tf @@ -0,0 +1,162 @@ +# Global Terraform +variable "environment" { + description = "Architecture environment" + type = string +} + +# Global DataDog +variable "message" { + description = "Message sent when a serverfarms monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +# Azure serverfarms specific variables + +# Status +variable "status_enabled" { + description = "Flag to enable the serverfarms status monitor" + type = string + default = "true" +} + +variable "status_message" { + description = "Custom message for serverfarm status monitor" + type = string + default = "" +} + +variable "status_extra_tags" { + description = "Extra tags for serverfarms status monitor" + type = list(string) + default = [] +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for serverfarms status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for serverfarms status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +# CPU percentage +variable "cpu_percentage_enabled" { + description = "Flag to enable the serverfarms cpu_percentage monitor" + type = string + default = "true" +} + +variable "cpu_percentage_message" { + description = "Custom message for serverfarm cpu_percentage monitor" + type = string + default = "" +} + +variable "cpu_percentage_extra_tags" { + description = "Extra tags for serverfarms cpu_percentage monitor" + type = list(string) + default = [] +} + +variable "cpu_percentage_time_aggregator" { + description = "Monitor aggregator for serverfarms cpu_percentage [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cpu_percentage_timeframe" { + description = "Monitor timeframe for serverfarms cpu_percentage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_10m" +} + +variable "cpu_percentage_threshold_critical" { + description = "CPU percentage (critical threshold)" + default = 95 +} + +variable "cpu_percentage_threshold_warning" { + description = "CPU percentage (warning threshold)" + default = 90 +} + +# Memory percentage +variable "memory_percentage_enabled" { + description = "Flag to enable the serverfarms memory_percentage monitor" + type = string + default = "true" +} + +variable "memory_percentage_message" { + description = "Custom message for serverfarm memory_percentage monitor" + type = string + default = "" +} + +variable "memory_percentage_extra_tags" { + description = "Extra tags for serverfarms memory_percentage monitor" + type = list(string) + default = [] +} + +variable "memory_percentage_time_aggregator" { + description = "Monitor aggregator for serverfarms memory_percentage [available values: min, max or avg]" + type = string + default = "min" +} + +variable "memory_percentage_timeframe" { + description = "Monitor timeframe for serverfarms memory_percentage [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "memory_percentage_threshold_critical" { + description = "Memory percentage (critical threshold)" + default = 95 +} + +variable "memory_percentage_threshold_warning" { + description = "Memory percentage (warning threshold)" + default = 90 +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/serverfarms/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/serverfarms/modules.tf new file mode 100755 index 0000000..ed11dfa --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/serverfarms/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_serverfarms" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/serverfarms/monitors-azure-serverfarms.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/serverfarms/monitors-azure-serverfarms.tf new file mode 100755 index 0000000..3e56420 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/serverfarms/monitors-azure-serverfarms.tf @@ -0,0 +1,86 @@ +resource "datadog_monitor" "status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Serverfarm is down" + message = coalesce(var.status_message, var.message) + type = "query alert" + + query = < ${var.cpu_percentage_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.cpu_percentage_threshold_warning + critical = var.cpu_percentage_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:serverfarms", "team:claranet", "created-by:terraform"], var.cpu_percentage_extra_tags) +} + +resource "datadog_monitor" "memory_percentage" { + count = var.memory_percentage_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Serverfarm memory percentage is too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.memory_percentage_message, var.message) + type = "query alert" + + query = < ${var.memory_percentage_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.memory_percentage_threshold_warning + critical = var.memory_percentage_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:serverfarms", "team:claranet", "created-by:terraform"], var.memory_percentage_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/serverfarms/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/serverfarms/outputs.tf new file mode 100755 index 0000000..6ab4b6c --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/serverfarms/outputs.tf @@ -0,0 +1,15 @@ +output "cpu_percentage_id" { + description = "id for monitor cpu_percentage" + value = datadog_monitor.cpu_percentage.*.id +} + +output "memory_percentage_id" { + description = "id for monitor memory_percentage" + value = datadog_monitor.memory_percentage.*.id +} + +output "status_id" { + description = "id for monitor status" + value = datadog_monitor.status.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/serverfarms/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/serverfarms/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/serverfarms/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/servicebus/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/servicebus/README.md new file mode 100755 index 0000000..9b9c6f3 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/servicebus/README.md @@ -0,0 +1,105 @@ +# CLOUD AZURE SERVICEBUS DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-servicebus" { + source = "claranet/monitors/datadog//cloud/azure/servicebus" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Service Bus has no active connection +- Service Bus is down +- Service Bus server errors rate is high +- Service Bus user errors rate is high + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.service_bus_no_active_connections](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.service_bus_server_errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.service_bus_user_errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.servicebus_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [no\_active\_connections\_enabled](#input\_no\_active\_connections\_enabled) | Flag to enable Service Bus no active connections monitor | `string` | `"true"` | no | +| [no\_active\_connections\_extra\_tags](#input\_no\_active\_connections\_extra\_tags) | Extra tags for Service Bus no active connections monitor | `list(string)` | `[]` | no | +| [no\_active\_connections\_message](#input\_no\_active\_connections\_message) | Custom message for Service Bus no active connections monitor | `string` | `""` | no | +| [no\_active\_connections\_time\_aggregator](#input\_no\_active\_connections\_time\_aggregator) | Monitor aggregator for Service Bus no active connections [available values: min, max or avg] | `string` | `"max"` | no | +| [no\_active\_connections\_timeframe](#input\_no\_active\_connections\_timeframe) | Monitor timeframe for Service Bus no active connections [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [server\_errors\_enabled](#input\_server\_errors\_enabled) | Flag to enable Service Bus server errors monitor | `string` | `"true"` | no | +| [server\_errors\_extra\_tags](#input\_server\_errors\_extra\_tags) | Extra tags for Service Bus server errors monitor | `list(string)` | `[]` | no | +| [server\_errors\_message](#input\_server\_errors\_message) | Custom message for Service Bus server errors monitor | `string` | `""` | no | +| [server\_errors\_threshold\_critical](#input\_server\_errors\_threshold\_critical) | Critical threshold for Service Bus server errors monitor | `number` | `90` | no | +| [server\_errors\_threshold\_warning](#input\_server\_errors\_threshold\_warning) | Warning threshold for Service Bus server errors monitor | `number` | `50` | no | +| [server\_errors\_time\_aggregator](#input\_server\_errors\_time\_aggregator) | Monitor aggregator for Service Bus server errors [available values: min, max or avg] | `string` | `"min"` | no | +| [server\_errors\_timeframe](#input\_server\_errors\_timeframe) | Monitor timeframe for Service Bus server errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [servicebus\_status\_no\_data\_timeframe](#input\_servicebus\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable Service Bus status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for Service Bus status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for Service Bus status monitor | `string` | `""` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for Service Bus status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for Service Bus status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [user\_errors\_enabled](#input\_user\_errors\_enabled) | Flag to enable Service Bus user errors monitor | `string` | `"true"` | no | +| [user\_errors\_extra\_tags](#input\_user\_errors\_extra\_tags) | Extra tags for Service Bus user errors monitor | `list(string)` | `[]` | no | +| [user\_errors\_message](#input\_user\_errors\_message) | Custom message for Service Bus user errors monitor | `string` | `""` | no | +| [user\_errors\_threshold\_critical](#input\_user\_errors\_threshold\_critical) | Critical threshold for Service Bus user errors monitor | `number` | `90` | no | +| [user\_errors\_threshold\_warning](#input\_user\_errors\_threshold\_warning) | Warning threshold for Service Bus user errors monitor | `number` | `50` | no | +| [user\_errors\_time\_aggregator](#input\_user\_errors\_time\_aggregator) | Monitor aggregator for Service Bus user errors [available values: min, max or avg] | `string` | `"min"` | no | +| [user\_errors\_timeframe](#input\_user\_errors\_timeframe) | Monitor timeframe for Service Bus user errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [service\_bus\_no\_active\_connections\_id](#output\_service\_bus\_no\_active\_connections\_id) | id for monitor service\_bus\_no\_active\_connections | +| [service\_bus\_server\_errors\_id](#output\_service\_bus\_server\_errors\_id) | id for monitor service\_bus\_server\_errors | +| [service\_bus\_user\_errors\_id](#output\_service\_bus\_user\_errors\_id) | id for monitor service\_bus\_user\_errors | +| [servicebus\_status\_id](#output\_servicebus\_status\_id) | id for monitor servicebus\_status | +## Related documentation + +DataDog documentation : [https://docs.datadoghq.com/integrations/azure/](https://docs.datadoghq.com/integrations/azure/) +You must search `servicebus`, there is no integration for now. + +Azure metrics documentation : [https://docs.microsoft.com/fr-fr/azure/monitoring-and-diagnostics/monitoring-supported-metrics#microsoftservicebusnamespaces](https://docs.microsoft.com/fr-fr/azure/monitoring-and-diagnostics/monitoring-supported-metrics#microsoftservicebusnamespaces) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/servicebus/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/servicebus/inputs.tf new file mode 100755 index 0000000..cf594ed --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/servicebus/inputs.tf @@ -0,0 +1,192 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "servicebus_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Azure Service Bus specific variables +variable "status_enabled" { + description = "Flag to enable Service Bus status monitor" + type = string + default = "true" +} + +variable "status_extra_tags" { + description = "Extra tags for Service Bus status monitor" + type = list(string) + default = [] +} + +variable "status_message" { + description = "Custom message for Service Bus status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for Service Bus status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for Service Bus status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + default = "last_5m" +} + +variable "no_active_connections_enabled" { + description = "Flag to enable Service Bus no active connections monitor" + type = string + default = "true" +} + +variable "no_active_connections_extra_tags" { + description = "Extra tags for Service Bus no active connections monitor" + type = list(string) + default = [] +} + +variable "no_active_connections_message" { + description = "Custom message for Service Bus no active connections monitor" + type = string + default = "" +} + +variable "no_active_connections_time_aggregator" { + description = "Monitor aggregator for Service Bus no active connections [available values: min, max or avg]" + type = string + default = "max" +} + +variable "no_active_connections_timeframe" { + description = "Monitor timeframe for Service Bus no active connections [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "server_errors_message" { + description = "Custom message for Service Bus server errors monitor" + type = string + default = "" +} + +variable "server_errors_enabled" { + description = "Flag to enable Service Bus server errors monitor" + type = string + default = "true" +} + +variable "server_errors_extra_tags" { + description = "Extra tags for Service Bus server errors monitor" + type = list(string) + default = [] +} + +variable "server_errors_time_aggregator" { + description = "Monitor aggregator for Service Bus server errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "server_errors_timeframe" { + description = "Monitor timeframe for Service Bus server errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "server_errors_threshold_critical" { + description = "Critical threshold for Service Bus server errors monitor" + default = 90 +} + +variable "server_errors_threshold_warning" { + description = "Warning threshold for Service Bus server errors monitor" + default = 50 +} + +variable "user_errors_message" { + description = "Custom message for Service Bus user errors monitor" + type = string + default = "" +} + +variable "user_errors_enabled" { + description = "Flag to enable Service Bus user errors monitor" + type = string + default = "true" +} + +variable "user_errors_extra_tags" { + description = "Extra tags for Service Bus user errors monitor" + type = list(string) + default = [] +} + +variable "user_errors_time_aggregator" { + description = "Monitor aggregator for Service Bus user errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "user_errors_timeframe" { + description = "Monitor timeframe for Service Bus user errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "user_errors_threshold_critical" { + description = "Critical threshold for Service Bus user errors monitor" + default = 90 +} + +variable "user_errors_threshold_warning" { + description = "Warning threshold for Service Bus user errors monitor" + default = 50 +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/servicebus/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/servicebus/modules.tf new file mode 100755 index 0000000..4abc459 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/servicebus/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_servicebus" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/servicebus/monitors-service-bus.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/servicebus/monitors-service-bus.tf new file mode 100755 index 0000000..4443ee7 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/servicebus/monitors-service-bus.tf @@ -0,0 +1,113 @@ +resource "datadog_monitor" "servicebus_status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Service Bus is down" + message = coalesce(var.status_message, var.message) + type = "query alert" + + query = < ${var.user_errors_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.user_errors_threshold_critical + warning = var.user_errors_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:servicebus", "team:claranet", "created-by:terraform"], var.user_errors_extra_tags) +} + +resource "datadog_monitor" "service_bus_server_errors" { + count = var.server_errors_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Service Bus server errors rate is high {{#is_alert}}{{comparator}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{comparator}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.server_errors_message, var.message) + type = "query alert" + + query = < ${var.server_errors_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.server_errors_threshold_critical + warning = var.server_errors_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:servicebus", "team:claranet", "created-by:terraform"], var.server_errors_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/servicebus/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/servicebus/outputs.tf new file mode 100755 index 0000000..5344f91 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/servicebus/outputs.tf @@ -0,0 +1,20 @@ +output "service_bus_no_active_connections_id" { + description = "id for monitor service_bus_no_active_connections" + value = datadog_monitor.service_bus_no_active_connections.*.id +} + +output "service_bus_server_errors_id" { + description = "id for monitor service_bus_server_errors" + value = datadog_monitor.service_bus_server_errors.*.id +} + +output "service_bus_user_errors_id" { + description = "id for monitor service_bus_user_errors" + value = datadog_monitor.service_bus_user_errors.*.id +} + +output "servicebus_status_id" { + description = "id for monitor servicebus_status" + value = datadog_monitor.servicebus_status.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/servicebus/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/servicebus/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/servicebus/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-database/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-database/README.md new file mode 100755 index 0000000..104b8ba --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-database/README.md @@ -0,0 +1,115 @@ +# CLOUD AZURE SQL-DATABASE DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-sql-database" { + source = "claranet/monitors/datadog//cloud/azure/sql-database" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- SQL Database CPU too high +- SQL Database Deadlocks too high +- SQL Database DTU Consumption too high +- SQL Database high disk usage +- SQL Database is down + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.sql-database_cpu](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.sql-database_deadlocks_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.sql-database_dtu_consumption_high](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.sql-database_free_space_low](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_enabled](#input\_cpu\_enabled) | Flag to enable SQL CPU monitor | `string` | `"true"` | no | +| [cpu\_extra\_tags](#input\_cpu\_extra\_tags) | Extra tags for SQL CPU monitor | `list(string)` | `[]` | no | +| [cpu\_message](#input\_cpu\_message) | Custom message for SQL CPU monitor | `string` | `""` | no | +| [cpu\_threshold\_critical](#input\_cpu\_threshold\_critical) | CPU usage in percent (critical threshold) | `string` | `"90"` | no | +| [cpu\_threshold\_warning](#input\_cpu\_threshold\_warning) | CPU usage in percent (warning threshold) | `string` | `"80"` | no | +| [cpu\_time\_aggregator](#input\_cpu\_time\_aggregator) | Monitor aggregator for SQL CPU [available values: min, max or avg] | `string` | `"min"` | no | +| [cpu\_timeframe](#input\_cpu\_timeframe) | Monitor timeframe for SQL CPU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [deadlock\_enabled](#input\_deadlock\_enabled) | Flag to enable SQL Deadlock monitor | `string` | `"true"` | no | +| [deadlock\_extra\_tags](#input\_deadlock\_extra\_tags) | Extra tags for SQL Deadlock monitor | `list(string)` | `[]` | no | +| [deadlock\_message](#input\_deadlock\_message) | Custom message for SQL Deadlock monitor | `string` | `""` | no | +| [deadlock\_threshold\_critical](#input\_deadlock\_threshold\_critical) | Amount of Deadlocks (critical threshold) | `string` | `"1"` | no | +| [deadlock\_timeframe](#input\_deadlock\_timeframe) | Monitor timeframe for SQL Deadlock [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [diskspace\_enabled](#input\_diskspace\_enabled) | Flag to enable SQL disk space monitor | `string` | `"true"` | no | +| [diskspace\_extra\_tags](#input\_diskspace\_extra\_tags) | Extra tags for SQL disk space monitor | `list(string)` | `[]` | no | +| [diskspace\_message](#input\_diskspace\_message) | Custom message for SQL disk space monitor | `string` | `""` | no | +| [diskspace\_threshold\_critical](#input\_diskspace\_threshold\_critical) | Disk space used in percent (critical threshold) | `string` | `"90"` | no | +| [diskspace\_threshold\_warning](#input\_diskspace\_threshold\_warning) | Disk space used in percent (warning threshold) | `string` | `"80"` | no | +| [diskspace\_time\_aggregator](#input\_diskspace\_time\_aggregator) | Monitor aggregator for SQL disk space [available values: min, max or avg] | `string` | `"max"` | no | +| [diskspace\_timeframe](#input\_diskspace\_timeframe) | Monitor timeframe for SQL disk space [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [dtu\_enabled](#input\_dtu\_enabled) | Flag to enable SQL DTU monitor | `string` | `"true"` | no | +| [dtu\_extra\_tags](#input\_dtu\_extra\_tags) | Extra tags for SQL DTU monitor | `list(string)` | `[]` | no | +| [dtu\_message](#input\_dtu\_message) | Custom message for SQL DTU monitor | `string` | `""` | no | +| [dtu\_threshold\_critical](#input\_dtu\_threshold\_critical) | Amount of DTU used (critical threshold) | `string` | `"90"` | no | +| [dtu\_threshold\_warning](#input\_dtu\_threshold\_warning) | Amount of DTU used (warning threshold) | `string` | `"85"` | no | +| [dtu\_time\_aggregator](#input\_dtu\_time\_aggregator) | Monitor aggregator for SQL DTU [available values: min, max or avg] | `string` | `"avg"` | no | +| [dtu\_timeframe](#input\_dtu\_timeframe) | Monitor timeframe for SQL DTU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable Redis status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for Redis status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for Redis status monitor | `string` | `""` | no | +| [status\_no\_data\_timeframe](#input\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for Redis status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for Redis status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [sql-database\_cpu\_id](#output\_sql-database\_cpu\_id) | id for monitor sql-database\_cpu | +| [sql-database\_deadlocks\_count\_id](#output\_sql-database\_deadlocks\_count\_id) | id for monitor sql-database\_deadlocks\_count | +| [sql-database\_dtu\_consumption\_high\_id](#output\_sql-database\_dtu\_consumption\_high\_id) | id for monitor sql-database\_dtu\_consumption\_high | +| [sql-database\_free\_space\_low\_id](#output\_sql-database\_free\_space\_low\_id) | id for monitor sql-database\_free\_space\_low | +| [status\_id](#output\_status\_id) | id for monitor status | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure_sql_database/](https://docs.datadoghq.com/integrations/azure_sql_database/) + +Azure SQL Database metrics documentation: [https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-supported#microsoftsqlserversdatabases](https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-supported#microsoftsqlserversdatabases) + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-database/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-database/inputs.tf new file mode 100755 index 0000000..6fffd14 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-database/inputs.tf @@ -0,0 +1,233 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Azure SQL Database specific variables + +variable "status_enabled" { + description = "Flag to enable Redis status monitor" + type = string + default = "true" +} + +variable "status_extra_tags" { + description = "Extra tags for Redis status monitor" + type = list(string) + default = [] +} + +variable "status_message" { + description = "Custom message for Redis status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for Redis status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for Redis status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "cpu_enabled" { + description = "Flag to enable SQL CPU monitor" + type = string + default = "true" +} + +variable "cpu_extra_tags" { + description = "Extra tags for SQL CPU monitor" + type = list(string) + default = [] +} + +variable "cpu_message" { + description = "Custom message for SQL CPU monitor" + type = string + default = "" +} + +variable "cpu_time_aggregator" { + description = "Monitor aggregator for SQL CPU [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cpu_timeframe" { + description = "Monitor timeframe for SQL CPU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "cpu_threshold_warning" { + description = "CPU usage in percent (warning threshold)" + default = "80" +} + +variable "cpu_threshold_critical" { + description = "CPU usage in percent (critical threshold)" + default = "90" +} + +variable "diskspace_enabled" { + description = "Flag to enable SQL disk space monitor" + type = string + default = "true" +} + +variable "diskspace_extra_tags" { + description = "Extra tags for SQL disk space monitor" + type = list(string) + default = [] +} + +variable "diskspace_message" { + description = "Custom message for SQL disk space monitor" + type = string + default = "" +} + +variable "diskspace_time_aggregator" { + description = "Monitor aggregator for SQL disk space [available values: min, max or avg]" + type = string + default = "max" +} + +variable "diskspace_timeframe" { + description = "Monitor timeframe for SQL disk space [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "diskspace_threshold_warning" { + description = "Disk space used in percent (warning threshold)" + default = "80" +} + +variable "diskspace_threshold_critical" { + description = "Disk space used in percent (critical threshold)" + default = "90" +} + +variable "dtu_enabled" { + description = "Flag to enable SQL DTU monitor" + type = string + default = "true" +} + +variable "dtu_extra_tags" { + description = "Extra tags for SQL DTU monitor" + type = list(string) + default = [] +} + +variable "dtu_message" { + description = "Custom message for SQL DTU monitor" + type = string + default = "" +} + +variable "dtu_time_aggregator" { + description = "Monitor aggregator for SQL DTU [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "dtu_timeframe" { + description = "Monitor timeframe for SQL DTU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "dtu_threshold_warning" { + description = "Amount of DTU used (warning threshold)" + default = "85" +} + +variable "dtu_threshold_critical" { + description = "Amount of DTU used (critical threshold)" + default = "90" +} + +variable "deadlock_enabled" { + description = "Flag to enable SQL Deadlock monitor" + type = string + default = "true" +} + +variable "deadlock_extra_tags" { + description = "Extra tags for SQL Deadlock monitor" + type = list(string) + default = [] +} + +variable "deadlock_message" { + description = "Custom message for SQL Deadlock monitor" + type = string + default = "" +} + +variable "deadlock_timeframe" { + description = "Monitor timeframe for SQL Deadlock [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "deadlock_threshold_critical" { + description = "Amount of Deadlocks (critical threshold)" + default = "1" +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-database/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-database/modules.tf new file mode 100755 index 0000000..6f0c6de --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-database/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_sql-database" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-database/monitors-sql-database.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-database/monitors-sql-database.tf new file mode 100755 index 0000000..f608ef0 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-database/monitors-sql-database.tf @@ -0,0 +1,145 @@ +resource "datadog_monitor" "status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] SQL Database is down" + message = coalesce(var.status_message, var.message) + type = "query alert" + + query = < ${var.cpu_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.cpu_threshold_critical + warning = var.cpu_threshold_warning + } + + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:sql-database", "team:claranet", "created-by:terraform"], var.cpu_extra_tags) +} + +resource "datadog_monitor" "sql-database_free_space_low" { + count = var.diskspace_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] SQL Database high disk usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.diskspace_message, var.message) + type = "query alert" + + query = < ${var.diskspace_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.diskspace_threshold_warning + critical = var.diskspace_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:sql-database", "team:claranet", "created-by:terraform"], var.diskspace_extra_tags) +} + +resource "datadog_monitor" "sql-database_dtu_consumption_high" { + count = var.dtu_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] SQL Database DTU Consumption too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.dtu_message, var.message) + type = "query alert" + + query = < ${var.dtu_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.dtu_threshold_warning + critical = var.dtu_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:sql-database", "team:claranet", "created-by:terraform"], var.dtu_extra_tags) +} + +resource "datadog_monitor" "sql-database_deadlocks_count" { + count = var.deadlock_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] SQL Database Deadlocks too high {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.deadlock_message, var.message) + type = "query alert" + + query = < ${var.deadlock_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.deadlock_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:sql-database", "team:claranet", "created-by:terraform"], var.deadlock_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-database/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-database/outputs.tf new file mode 100755 index 0000000..add5c74 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-database/outputs.tf @@ -0,0 +1,25 @@ +output "sql-database_cpu_id" { + description = "id for monitor sql-database_cpu" + value = datadog_monitor.sql-database_cpu.*.id +} + +output "sql-database_deadlocks_count_id" { + description = "id for monitor sql-database_deadlocks_count" + value = datadog_monitor.sql-database_deadlocks_count.*.id +} + +output "sql-database_dtu_consumption_high_id" { + description = "id for monitor sql-database_dtu_consumption_high" + value = datadog_monitor.sql-database_dtu_consumption_high.*.id +} + +output "sql-database_free_space_low_id" { + description = "id for monitor sql-database_free_space_low" + value = datadog_monitor.sql-database_free_space_low.*.id +} + +output "status_id" { + description = "id for monitor status" + value = datadog_monitor.status.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-database/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-database/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-database/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-elasticpool/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-elasticpool/README.md new file mode 100755 index 0000000..4bbf3c5 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-elasticpool/README.md @@ -0,0 +1,98 @@ +# CLOUD AZURE SQL-ELASTICPOOL DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-sql-elasticpool" { + source = "claranet/monitors/datadog//cloud/azure/sql-elasticpool" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- SQL Elastic Pool CPU too high +- SQL Elastic Pool DTU Consumption too high +- SQL Elastic Pool high disk usage + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.sql_elasticpool_cpu](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.sql_elasticpool_dtu_consumption_high](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.sql_elasticpool_free_space_low](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_enabled](#input\_cpu\_enabled) | Flag to enable SQL Elastic Pool CPU monitor | `string` | `"true"` | no | +| [cpu\_extra\_tags](#input\_cpu\_extra\_tags) | Extra tags for SQL Elastic Pool CPU monitor | `list(string)` | `[]` | no | +| [cpu\_message](#input\_cpu\_message) | Custom message for SQL Elastic Pool CPU monitor | `string` | `""` | no | +| [cpu\_threshold\_critical](#input\_cpu\_threshold\_critical) | CPU usage in percent (critical threshold) | `string` | `"90"` | no | +| [cpu\_threshold\_warning](#input\_cpu\_threshold\_warning) | CPU usage in percent (warning threshold) | `string` | `"80"` | no | +| [cpu\_time\_aggregator](#input\_cpu\_time\_aggregator) | Monitor aggregator for SQL Elastic Pool CPU [available values: min, max or avg] | `string` | `"min"` | no | +| [cpu\_timeframe](#input\_cpu\_timeframe) | Monitor timeframe for SQL Elastic Pool CPU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [diskspace\_enabled](#input\_diskspace\_enabled) | Flag to enable SQL Elastic Pool disk space monitor | `string` | `"true"` | no | +| [diskspace\_extra\_tags](#input\_diskspace\_extra\_tags) | Extra tags for SQL Elastic Pool disk space monitor | `list(string)` | `[]` | no | +| [diskspace\_message](#input\_diskspace\_message) | Custom message for SQL Elastic Pool disk space monitor | `string` | `""` | no | +| [diskspace\_threshold\_critical](#input\_diskspace\_threshold\_critical) | Disk space used in percent (critical threshold) | `string` | `"90"` | no | +| [diskspace\_threshold\_warning](#input\_diskspace\_threshold\_warning) | Disk space used in percent (warning threshold) | `string` | `"80"` | no | +| [diskspace\_time\_aggregator](#input\_diskspace\_time\_aggregator) | Monitor aggregator for SQL Elastic Pool disk space [available values: min, max or avg] | `string` | `"max"` | no | +| [diskspace\_timeframe](#input\_diskspace\_timeframe) | Monitor timeframe for SQL Elastic Pool disk space [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [dtu\_enabled](#input\_dtu\_enabled) | Flag to enable SQL Elastic Pool DTU monitor | `string` | `"true"` | no | +| [dtu\_extra\_tags](#input\_dtu\_extra\_tags) | Extra tags for SQL Elastic Pool DTU monitor | `list(string)` | `[]` | no | +| [dtu\_message](#input\_dtu\_message) | Custom message for SQL Elastic Pool DTU monitor | `string` | `""` | no | +| [dtu\_threshold\_critical](#input\_dtu\_threshold\_critical) | Amount of DTU used (critical threshold) | `string` | `"90"` | no | +| [dtu\_threshold\_warning](#input\_dtu\_threshold\_warning) | Amount of DTU used (warning threshold) | `string` | `"85"` | no | +| [dtu\_time\_aggregator](#input\_dtu\_time\_aggregator) | Monitor aggregator for SQL Elastic Pool DTU [available values: min, max or avg] | `string` | `"avg"` | no | +| [dtu\_timeframe](#input\_dtu\_timeframe) | Monitor timeframe for SQL Elastic Pool DTU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [sql\_elasticpool\_cpu\_no\_data\_timeframe](#input\_sql\_elasticpool\_cpu\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `30` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [sql\_elasticpool\_cpu\_id](#output\_sql\_elasticpool\_cpu\_id) | id for monitor sql\_elasticpool\_cpu | +| [sql\_elasticpool\_dtu\_consumption\_high\_id](#output\_sql\_elasticpool\_dtu\_consumption\_high\_id) | id for monitor sql\_elasticpool\_dtu\_consumption\_high | +| [sql\_elasticpool\_free\_space\_low\_id](#output\_sql\_elasticpool\_free\_space\_low\_id) | id for monitor sql\_elasticpool\_free\_space\_low | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure_sql_elastic_pool/](https://docs.datadoghq.com/integrations/azure_sql_elastic_pool/) + +Azure SQL Elastic Pool metrics documentation: [https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-supported#microsoftsqlserverselasticpools](https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-supported#microsoftsqlserverselasticpools) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-elasticpool/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-elasticpool/inputs.tf new file mode 100755 index 0000000..ac04bed --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-elasticpool/inputs.tf @@ -0,0 +1,174 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "sql_elasticpool_cpu_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 30 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Azure SQL Elastic Pool specific variables + +variable "cpu_enabled" { + description = "Flag to enable SQL Elastic Pool CPU monitor" + type = string + default = "true" +} + +variable "cpu_extra_tags" { + description = "Extra tags for SQL Elastic Pool CPU monitor" + type = list(string) + default = [] +} + +variable "cpu_message" { + description = "Custom message for SQL Elastic Pool CPU monitor" + type = string + default = "" +} + +variable "cpu_time_aggregator" { + description = "Monitor aggregator for SQL Elastic Pool CPU [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cpu_timeframe" { + description = "Monitor timeframe for SQL Elastic Pool CPU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "cpu_threshold_warning" { + description = "CPU usage in percent (warning threshold)" + default = "80" +} + +variable "cpu_threshold_critical" { + description = "CPU usage in percent (critical threshold)" + default = "90" +} + +variable "diskspace_enabled" { + description = "Flag to enable SQL Elastic Pool disk space monitor" + type = string + default = "true" +} + +variable "diskspace_extra_tags" { + description = "Extra tags for SQL Elastic Pool disk space monitor" + type = list(string) + default = [] +} + +variable "diskspace_message" { + description = "Custom message for SQL Elastic Pool disk space monitor" + type = string + default = "" +} + +variable "diskspace_time_aggregator" { + description = "Monitor aggregator for SQL Elastic Pool disk space [available values: min, max or avg]" + type = string + default = "max" +} + +variable "diskspace_timeframe" { + description = "Monitor timeframe for SQL Elastic Pool disk space [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "diskspace_threshold_warning" { + description = "Disk space used in percent (warning threshold)" + default = "80" +} + +variable "diskspace_threshold_critical" { + description = "Disk space used in percent (critical threshold)" + default = "90" +} + +variable "dtu_enabled" { + description = "Flag to enable SQL Elastic Pool DTU monitor" + type = string + default = "true" +} + +variable "dtu_extra_tags" { + description = "Extra tags for SQL Elastic Pool DTU monitor" + type = list(string) + default = [] +} + +variable "dtu_message" { + description = "Custom message for SQL Elastic Pool DTU monitor" + type = string + default = "" +} + +variable "dtu_time_aggregator" { + description = "Monitor aggregator for SQL Elastic Pool DTU [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "dtu_timeframe" { + description = "Monitor timeframe for SQL Elastic Pool DTU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "dtu_threshold_warning" { + description = "Amount of DTU used (warning threshold)" + default = "85" +} + +variable "dtu_threshold_critical" { + description = "Amount of DTU used (critical threshold)" + default = "90" +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-elasticpool/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-elasticpool/modules.tf new file mode 100755 index 0000000..6c5206d --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-elasticpool/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_sql-elasticpool" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-elasticpool/monitors-sql-elasticpool.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-elasticpool/monitors-sql-elasticpool.tf new file mode 100755 index 0000000..c65a1a1 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-elasticpool/monitors-sql-elasticpool.tf @@ -0,0 +1,91 @@ +resource "datadog_monitor" "sql_elasticpool_cpu" { + count = var.cpu_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] SQL Elastic Pool CPU too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cpu_message, var.message) + type = "query alert" + + query = < ${var.cpu_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.cpu_threshold_critical + warning = var.cpu_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = var.notify_no_data + no_data_timeframe = var.sql_elasticpool_cpu_no_data_timeframe + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:sql-elasticpool", "team:claranet", "created-by:terraform"], var.cpu_extra_tags) +} + +resource "datadog_monitor" "sql_elasticpool_free_space_low" { + count = var.diskspace_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] SQL Elastic Pool high disk usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.diskspace_message, var.message) + type = "query alert" + + query = < ${var.diskspace_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.diskspace_threshold_warning + critical = var.diskspace_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:sql-elasticpool", "team:claranet", "created-by:terraform"], var.diskspace_extra_tags) +} + +resource "datadog_monitor" "sql_elasticpool_dtu_consumption_high" { + count = var.dtu_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] SQL Elastic Pool DTU Consumption too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.dtu_message, var.message) + type = "query alert" + + query = < ${var.dtu_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.dtu_threshold_warning + critical = var.dtu_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:sql-elasticpool", "team:claranet", "created-by:terraform"], var.dtu_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-elasticpool/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-elasticpool/outputs.tf new file mode 100755 index 0000000..7c7d733 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-elasticpool/outputs.tf @@ -0,0 +1,15 @@ +output "sql_elasticpool_cpu_id" { + description = "id for monitor sql_elasticpool_cpu" + value = datadog_monitor.sql_elasticpool_cpu.*.id +} + +output "sql_elasticpool_dtu_consumption_high_id" { + description = "id for monitor sql_elasticpool_dtu_consumption_high" + value = datadog_monitor.sql_elasticpool_dtu_consumption_high.*.id +} + +output "sql_elasticpool_free_space_low_id" { + description = "id for monitor sql_elasticpool_free_space_low" + value = datadog_monitor.sql_elasticpool_free_space_low.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-elasticpool/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-elasticpool/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/sql-elasticpool/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/storage/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/storage/README.md new file mode 100755 index 0000000..9a27848 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/storage/README.md @@ -0,0 +1,249 @@ +# CLOUD AZURE STORAGE DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-storage" { + source = "claranet/monitors/datadog//cloud/azure/storage" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Azure Blob Storage too many authorization errors +- Azure Blob Storage too many client_other errors +- Azure Blob Storage too many network errors +- Azure Blob Storage too many server_other errors +- Azure Blob Storage too many throttling errors +- Azure Blob Storage too many timeout errors +- Azure File Storage too many authorization errors +- Azure File Storage too many client_other errors +- Azure File Storage too many network errors +- Azure File Storage too many server_other errors +- Azure File Storage too many throttling errors +- Azure File Storage too many timeout errors +- Azure Queue Storage too many authorization errors +- Azure Queue Storage too many client_other errors +- Azure Queue Storage too many network errors +- Azure Queue Storage too many server_other errors +- Azure Queue Storage too many throttling errors +- Azure Queue Storage too many timeout errors +- Azure Storage Blob service too few successful requests +- Azure Storage Blob service too high end to end latency +- Azure Storage File service too few successful requests +- Azure Storage File service too high end to end latency +- Azure Storage is down +- Azure Storage Queue service too few successful requests +- Azure Storage Queue service too high end to end latency +- Azure Storage Table service too few successful requests +- Azure Storage Table service too high end to end latency +- Azure Table Storage too many authorization errors +- Azure Table Storage too many client_other errors +- Azure Table Storage too many network errors +- Azure Table Storage too many server_other errors +- Azure Table Storage too many throttling errors +- Azure Table Storage too many timeout errors + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | +| [filter-tags-authorization-error](#module\_filter-tags-authorization-error) | ../../../common/filter-tags | n/a | +| [filter-tags-blob](#module\_filter-tags-blob) | ../../../common/filter-tags | n/a | +| [filter-tags-client-other-error](#module\_filter-tags-client-other-error) | ../../../common/filter-tags | n/a | +| [filter-tags-client-other-error-blob](#module\_filter-tags-client-other-error-blob) | ../../../common/filter-tags | n/a | +| [filter-tags-network-error](#module\_filter-tags-network-error) | ../../../common/filter-tags | n/a | +| [filter-tags-server-other-error](#module\_filter-tags-server-other-error) | ../../../common/filter-tags | n/a | +| [filter-tags-success](#module\_filter-tags-success) | ../../../common/filter-tags | n/a | +| [filter-tags-success-blob](#module\_filter-tags-success-blob) | ../../../common/filter-tags | n/a | +| [filter-tags-throttling-error](#module\_filter-tags-throttling-error) | ../../../common/filter-tags | n/a | +| [filter-tags-timeout-error](#module\_filter-tags-timeout-error) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.blob_authorization_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.blob_client_other_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.blob_network_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.blob_server_other_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.blob_throttling_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.blob_timeout_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.blobservices_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.blobservices_requests_error](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.file_authorization_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.file_client_other_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.file_network_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.file_server_other_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.file_throttling_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.file_timeout_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.fileservices_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.fileservices_requests_error](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.queue_authorization_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.queue_client_other_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.queue_network_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.queue_server_other_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.queue_throttling_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.queue_timeout_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.queueservices_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.queueservices_requests_error](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.storage_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.table_authorization_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.table_client_other_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.table_network_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.table_server_other_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.table_throttling_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.table_timeout_error_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.tableservices_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.tableservices_requests_error](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [authorization\_error\_requests\_enabled](#input\_authorization\_error\_requests\_enabled) | Flag to enable Storage authorization errors monitor | `string` | `"true"` | no | +| [authorization\_error\_requests\_extra\_tags](#input\_authorization\_error\_requests\_extra\_tags) | Extra tags for Storage authorization errors monitor | `list(string)` | `[]` | no | +| [authorization\_error\_requests\_message](#input\_authorization\_error\_requests\_message) | Custom message for Storage authorization errors monitor | `string` | `""` | no | +| [authorization\_error\_requests\_threshold\_critical](#input\_authorization\_error\_requests\_threshold\_critical) | Maximum acceptable percent of authorization error requests for a storage | `number` | `90` | no | +| [authorization\_error\_requests\_threshold\_warning](#input\_authorization\_error\_requests\_threshold\_warning) | Warning regarding acceptable percent of authorization error requests for a storage | `number` | `50` | no | +| [authorization\_error\_requests\_time\_aggregator](#input\_authorization\_error\_requests\_time\_aggregator) | Monitor aggregator for Storage authorization errors [available values: min, max or avg] | `string` | `"min"` | no | +| [authorization\_error\_requests\_timeframe](#input\_authorization\_error\_requests\_timeframe) | Monitor timeframe for Storage authorization errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [availability\_enabled](#input\_availability\_enabled) | Flag to enable Storage availability monitor | `string` | `"true"` | no | +| [availability\_extra\_tags](#input\_availability\_extra\_tags) | Extra tags for Storage availability monitor | `list(string)` | `[]` | no | +| [availability\_message](#input\_availability\_message) | Custom message for Storage availability monitor | `string` | `""` | no | +| [availability\_threshold\_critical](#input\_availability\_threshold\_critical) | Minimum acceptable percent of availability for a storage | `number` | `50` | no | +| [availability\_threshold\_warning](#input\_availability\_threshold\_warning) | Warning regarding acceptable percent of availability for a storage | `number` | `90` | no | +| [availability\_time\_aggregator](#input\_availability\_time\_aggregator) | Monitor aggregator for Storage availability [available values: min, max or avg] | `string` | `"max"` | no | +| [availability\_timeframe](#input\_availability\_timeframe) | Monitor timeframe for Storage availability [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [client\_other\_error\_requests\_enabled](#input\_client\_other\_error\_requests\_enabled) | Flag to enable Storage other errors monitor | `string` | `"true"` | no | +| [client\_other\_error\_requests\_extra\_tags](#input\_client\_other\_error\_requests\_extra\_tags) | Extra tags for Storage other errors monitor | `list(string)` | `[]` | no | +| [client\_other\_error\_requests\_message](#input\_client\_other\_error\_requests\_message) | Custom message for Storage other errors monitor | `string` | `""` | no | +| [client\_other\_error\_requests\_threshold\_critical](#input\_client\_other\_error\_requests\_threshold\_critical) | Maximum acceptable percent of client other error requests for a storage | `number` | `90` | no | +| [client\_other\_error\_requests\_threshold\_warning](#input\_client\_other\_error\_requests\_threshold\_warning) | Warning regarding acceptable percent of client other error requests for a storage | `number` | `50` | no | +| [client\_other\_error\_requests\_time\_aggregator](#input\_client\_other\_error\_requests\_time\_aggregator) | Monitor aggregator for Storage other errors [available values: min, max or avg] | `string` | `"min"` | no | +| [client\_other\_error\_requests\_timeframe](#input\_client\_other\_error\_requests\_timeframe) | Monitor timeframe for Storage other errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [latency\_enabled](#input\_latency\_enabled) | Flag to enable Storage latency monitor | `string` | `"true"` | no | +| [latency\_extra\_tags](#input\_latency\_extra\_tags) | Extra tags for Storage latency monitor | `list(string)` | `[]` | no | +| [latency\_message](#input\_latency\_message) | Custom message for Storage latency monitor | `string` | `""` | no | +| [latency\_threshold\_critical](#input\_latency\_threshold\_critical) | Maximum acceptable end to end latency (ms) for a storage | `number` | `2000` | no | +| [latency\_threshold\_warning](#input\_latency\_threshold\_warning) | Warning regarding acceptable end to end latency (ms) for a storage | `number` | `1000` | no | +| [latency\_time\_aggregator](#input\_latency\_time\_aggregator) | Monitor aggregator for Storage latency [available values: min, max or avg] | `string` | `"min"` | no | +| [latency\_timeframe](#input\_latency\_timeframe) | Monitor timeframe for Storage latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when a Redis monitor is triggered | `any` | n/a | yes | +| [network\_error\_requests\_enabled](#input\_network\_error\_requests\_enabled) | Flag to enable Storage network errors monitor | `string` | `"true"` | no | +| [network\_error\_requests\_extra\_tags](#input\_network\_error\_requests\_extra\_tags) | Extra tags for Storage network errors monitor | `list(string)` | `[]` | no | +| [network\_error\_requests\_message](#input\_network\_error\_requests\_message) | Custom message for Storage network errors monitor | `string` | `""` | no | +| [network\_error\_requests\_threshold\_critical](#input\_network\_error\_requests\_threshold\_critical) | Maximum acceptable percent of network error requests for a storage | `number` | `90` | no | +| [network\_error\_requests\_threshold\_warning](#input\_network\_error\_requests\_threshold\_warning) | Warning regarding acceptable percent of network error requests for a storage | `number` | `50` | no | +| [network\_error\_requests\_time\_aggregator](#input\_network\_error\_requests\_time\_aggregator) | Monitor aggregator for Storage network errors [available values: min, max or avg] | `string` | `"min"` | no | +| [network\_error\_requests\_timeframe](#input\_network\_error\_requests\_timeframe) | Monitor timeframe for Storage network errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [server\_other\_error\_requests\_enabled](#input\_server\_other\_error\_requests\_enabled) | Flag to enable Storage server other errors monitor | `string` | `"true"` | no | +| [server\_other\_error\_requests\_extra\_tags](#input\_server\_other\_error\_requests\_extra\_tags) | Extra tags for Storage server other errors monitor | `list(string)` | `[]` | no | +| [server\_other\_error\_requests\_message](#input\_server\_other\_error\_requests\_message) | Custom message for Storage server other errors monitor | `string` | `""` | no | +| [server\_other\_error\_requests\_threshold\_critical](#input\_server\_other\_error\_requests\_threshold\_critical) | Maximum acceptable percent of server other error requests for a storage | `number` | `90` | no | +| [server\_other\_error\_requests\_threshold\_warning](#input\_server\_other\_error\_requests\_threshold\_warning) | Warning regarding acceptable percent of server other error requests for a storage | `number` | `50` | no | +| [server\_other\_error\_requests\_time\_aggregator](#input\_server\_other\_error\_requests\_time\_aggregator) | Monitor aggregator for Storage other errors [available values: min, max or avg] | `string` | `"min"` | no | +| [server\_other\_error\_requests\_timeframe](#input\_server\_other\_error\_requests\_timeframe) | Monitor timeframe for Storage server other errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable App Services status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for App Services status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for storage Services status monitor | `string` | `""` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for Storage Services status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for Storage Services status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [storage\_status\_no\_data\_timeframe](#input\_storage\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [successful\_requests\_enabled](#input\_successful\_requests\_enabled) | Flag to enable Storage sucessful requests monitor | `string` | `"true"` | no | +| [successful\_requests\_extra\_tags](#input\_successful\_requests\_extra\_tags) | Extra tags for Storage sucessful requests monitor | `list(string)` | `[]` | no | +| [successful\_requests\_message](#input\_successful\_requests\_message) | Custom message for Storage sucessful requests monitor | `string` | `""` | no | +| [successful\_requests\_time\_aggregator](#input\_successful\_requests\_time\_aggregator) | Monitor aggregator for Storage sucessful requests [available values: min, max or avg] | `string` | `"max"` | no | +| [successful\_requests\_timeframe](#input\_successful\_requests\_timeframe) | Monitor timeframe for Storage sucessful requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [successful\_storage\_requests\_threshold\_critical](#input\_successful\_storage\_requests\_threshold\_critical) | Minimum acceptable percent of successful requests for a storage | `number` | `90` | no | +| [successful\_storage\_requests\_threshold\_warning](#input\_successful\_storage\_requests\_threshold\_warning) | Warning regarding acceptable percent of successful requests for a storage | `number` | `70` | no | +| [throttling\_error\_requests\_enabled](#input\_throttling\_error\_requests\_enabled) | Flag to enable Storage throttling error monitor | `string` | `"true"` | no | +| [throttling\_error\_requests\_extra\_tags](#input\_throttling\_error\_requests\_extra\_tags) | Extra tags for Storage throttling error monitor | `list(string)` | `[]` | no | +| [throttling\_error\_requests\_message](#input\_throttling\_error\_requests\_message) | Custom message for Storage throttling error monitor | `string` | `""` | no | +| [throttling\_error\_requests\_threshold\_critical](#input\_throttling\_error\_requests\_threshold\_critical) | Maximum acceptable percent of throttling error requests for a storage | `number` | `90` | no | +| [throttling\_error\_requests\_threshold\_warning](#input\_throttling\_error\_requests\_threshold\_warning) | Warning regarding acceptable percent of throttling error requests for a storage | `number` | `50` | no | +| [throttling\_error\_requests\_time\_aggregator](#input\_throttling\_error\_requests\_time\_aggregator) | Monitor aggregator for Storage throttling errors [available values: min, max or avg] | `string` | `"min"` | no | +| [throttling\_error\_requests\_timeframe](#input\_throttling\_error\_requests\_timeframe) | Monitor timeframe for Storage throttling errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [timeout\_error\_requests\_enabled](#input\_timeout\_error\_requests\_enabled) | Flag to enable Storage timeout monitor | `string` | `"true"` | no | +| [timeout\_error\_requests\_extra\_tags](#input\_timeout\_error\_requests\_extra\_tags) | Extra tags for Storage timeout monitor | `list(string)` | `[]` | no | +| [timeout\_error\_requests\_message](#input\_timeout\_error\_requests\_message) | Custom message for Storage timeout monitor | `string` | `""` | no | +| [timeout\_error\_requests\_threshold\_critical](#input\_timeout\_error\_requests\_threshold\_critical) | Maximum acceptable percent of timeout error requests for a storage | `number` | `90` | no | +| [timeout\_error\_requests\_threshold\_warning](#input\_timeout\_error\_requests\_threshold\_warning) | Warning regarding acceptable percent of timeout error requests for a storage | `number` | `50` | no | +| [timeout\_error\_requests\_time\_aggregator](#input\_timeout\_error\_requests\_time\_aggregator) | Monitor aggregator for Storage timeout [available values: min, max or avg] | `string` | `"min"` | no | +| [timeout\_error\_requests\_timeframe](#input\_timeout\_error\_requests\_timeframe) | Monitor timeframe for Storage timeout [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [blob\_authorization\_error\_requests\_id](#output\_blob\_authorization\_error\_requests\_id) | id for monitor blob\_authorization\_error\_requests | +| [blob\_client\_other\_error\_requests\_id](#output\_blob\_client\_other\_error\_requests\_id) | id for monitor blob\_client\_other\_error\_requests | +| [blob\_network\_error\_requests\_id](#output\_blob\_network\_error\_requests\_id) | id for monitor blob\_network\_error\_requests | +| [blob\_server\_other\_error\_requests\_id](#output\_blob\_server\_other\_error\_requests\_id) | id for monitor blob\_server\_other\_error\_requests | +| [blob\_throttling\_error\_requests\_id](#output\_blob\_throttling\_error\_requests\_id) | id for monitor blob\_throttling\_error\_requests | +| [blob\_timeout\_error\_requests\_id](#output\_blob\_timeout\_error\_requests\_id) | id for monitor blob\_timeout\_error\_requests | +| [blobservices\_latency\_id](#output\_blobservices\_latency\_id) | id for monitor blobservices\_latency | +| [blobservices\_requests\_error\_id](#output\_blobservices\_requests\_error\_id) | id for monitor blobservices\_requests\_error | +| [file\_authorization\_error\_requests\_id](#output\_file\_authorization\_error\_requests\_id) | id for monitor file\_authorization\_error\_requests | +| [file\_client\_other\_error\_requests\_id](#output\_file\_client\_other\_error\_requests\_id) | id for monitor file\_client\_other\_error\_requests | +| [file\_network\_error\_requests\_id](#output\_file\_network\_error\_requests\_id) | id for monitor file\_network\_error\_requests | +| [file\_server\_other\_error\_requests\_id](#output\_file\_server\_other\_error\_requests\_id) | id for monitor file\_server\_other\_error\_requests | +| [file\_throttling\_error\_requests\_id](#output\_file\_throttling\_error\_requests\_id) | id for monitor file\_throttling\_error\_requests | +| [file\_timeout\_error\_requests\_id](#output\_file\_timeout\_error\_requests\_id) | id for monitor file\_timeout\_error\_requests | +| [fileservices\_latency\_id](#output\_fileservices\_latency\_id) | id for monitor fileservices\_latency | +| [fileservices\_requests\_error\_id](#output\_fileservices\_requests\_error\_id) | id for monitor fileservices\_requests\_error | +| [queue\_authorization\_error\_requests\_id](#output\_queue\_authorization\_error\_requests\_id) | id for monitor queue\_authorization\_error\_requests | +| [queue\_client\_other\_error\_requests\_id](#output\_queue\_client\_other\_error\_requests\_id) | id for monitor queue\_client\_other\_error\_requests | +| [queue\_network\_error\_requests\_id](#output\_queue\_network\_error\_requests\_id) | id for monitor queue\_network\_error\_requests | +| [queue\_server\_other\_error\_requests\_id](#output\_queue\_server\_other\_error\_requests\_id) | id for monitor queue\_server\_other\_error\_requests | +| [queue\_throttling\_error\_requests\_id](#output\_queue\_throttling\_error\_requests\_id) | id for monitor queue\_throttling\_error\_requests | +| [queue\_timeout\_error\_requests\_id](#output\_queue\_timeout\_error\_requests\_id) | id for monitor queue\_timeout\_error\_requests | +| [queueservices\_latency\_id](#output\_queueservices\_latency\_id) | id for monitor queueservices\_latency | +| [queueservices\_requests\_error\_id](#output\_queueservices\_requests\_error\_id) | id for monitor queueservices\_requests\_error | +| [storage\_status\_id](#output\_storage\_status\_id) | id for monitor storage\_status | +| [table\_authorization\_error\_requests\_id](#output\_table\_authorization\_error\_requests\_id) | id for monitor table\_authorization\_error\_requests | +| [table\_client\_other\_error\_requests\_id](#output\_table\_client\_other\_error\_requests\_id) | id for monitor table\_client\_other\_error\_requests | +| [table\_network\_error\_requests\_id](#output\_table\_network\_error\_requests\_id) | id for monitor table\_network\_error\_requests | +| [table\_server\_other\_error\_requests\_id](#output\_table\_server\_other\_error\_requests\_id) | id for monitor table\_server\_other\_error\_requests | +| [table\_throttling\_error\_requests\_id](#output\_table\_throttling\_error\_requests\_id) | id for monitor table\_throttling\_error\_requests | +| [table\_timeout\_error\_requests\_id](#output\_table\_timeout\_error\_requests\_id) | id for monitor table\_timeout\_error\_requests | +| [tableservices\_latency\_id](#output\_tableservices\_latency\_id) | id for monitor tableservices\_latency | +| [tableservices\_requests\_error\_id](#output\_tableservices\_requests\_error\_id) | id for monitor tableservices\_requests\_error | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure_storage/](https://docs.datadoghq.com/integrations/azure_storage/) + +DataDog blog: [https://www.datadoghq.com/blog/monitor-azure-storage-datadog/](https://www.datadoghq.com/blog/monitor-azure-storage-datadog/) + +Azure Storage metrics documentation: [https://docs.microsoft.com/en-us/azure/storage/common/storage-monitor-storage-account](https://docs.microsoft.com/en-us/azure/storage/common/storage-monitor-storage-account) + +Azure Storage metrics detailed documentation [https://docs.microsoft.com/en-us/rest/api/storageservices/storage-analytics-metrics-table-schema](https://docs.microsoft.com/en-us/rest/api/storageservices/storage-analytics-metrics-table-schema) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/storage/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/storage/inputs.tf new file mode 100755 index 0000000..9478a7f --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/storage/inputs.tf @@ -0,0 +1,442 @@ +# Global Terraform +variable "environment" { + description = "Architecture environment" + type = string +} + +# Global DataDog +variable "message" { + description = "Message sent when a Redis monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "storage_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Azure Storage specific variables +variable "availability_enabled" { + description = "Flag to enable Storage availability monitor" + type = string + default = "true" +} + +variable "availability_extra_tags" { + description = "Extra tags for Storage availability monitor" + type = list(string) + default = [] +} + +variable "availability_message" { + description = "Custom message for Storage availability monitor" + type = string + default = "" +} + +variable "availability_time_aggregator" { + description = "Monitor aggregator for Storage availability [available values: min, max or avg]" + type = string + default = "max" +} + +variable "availability_timeframe" { + description = "Monitor timeframe for Storage availability [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "availability_threshold_critical" { + description = "Minimum acceptable percent of availability for a storage" + default = 50 +} + +variable "availability_threshold_warning" { + description = "Warning regarding acceptable percent of availability for a storage" + default = 90 +} + +variable "successful_requests_enabled" { + description = "Flag to enable Storage sucessful requests monitor" + type = string + default = "true" +} + +variable "successful_requests_extra_tags" { + description = "Extra tags for Storage sucessful requests monitor" + type = list(string) + default = [] +} + +variable "successful_requests_message" { + description = "Custom message for Storage sucessful requests monitor" + type = string + default = "" +} + +variable "successful_requests_time_aggregator" { + description = "Monitor aggregator for Storage sucessful requests [available values: min, max or avg]" + type = string + default = "max" +} + +variable "successful_requests_timeframe" { + description = "Monitor timeframe for Storage sucessful requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "successful_storage_requests_threshold_critical" { + description = "Minimum acceptable percent of successful requests for a storage" + default = 90 +} + +variable "successful_storage_requests_threshold_warning" { + description = "Warning regarding acceptable percent of successful requests for a storage" + default = 70 +} + +variable "latency_enabled" { + description = "Flag to enable Storage latency monitor" + type = string + default = "true" +} + +variable "latency_extra_tags" { + description = "Extra tags for Storage latency monitor" + type = list(string) + default = [] +} + +variable "latency_message" { + description = "Custom message for Storage latency monitor" + type = string + default = "" +} + +variable "latency_time_aggregator" { + description = "Monitor aggregator for Storage latency [available values: min, max or avg]" + type = string + default = "min" +} + +variable "latency_timeframe" { + description = "Monitor timeframe for Storage latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "latency_threshold_critical" { + description = "Maximum acceptable end to end latency (ms) for a storage" + default = 2000 +} + +variable "latency_threshold_warning" { + description = "Warning regarding acceptable end to end latency (ms) for a storage" + default = 1000 +} + +variable "timeout_error_requests_enabled" { + description = "Flag to enable Storage timeout monitor" + type = string + default = "true" +} + +variable "timeout_error_requests_extra_tags" { + description = "Extra tags for Storage timeout monitor" + type = list(string) + default = [] +} + +variable "timeout_error_requests_message" { + description = "Custom message for Storage timeout monitor" + type = string + default = "" +} + +variable "timeout_error_requests_time_aggregator" { + description = "Monitor aggregator for Storage timeout [available values: min, max or avg]" + type = string + default = "min" +} + +variable "timeout_error_requests_timeframe" { + description = "Monitor timeframe for Storage timeout [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "timeout_error_requests_threshold_critical" { + description = "Maximum acceptable percent of timeout error requests for a storage" + default = 90 +} + +variable "timeout_error_requests_threshold_warning" { + description = "Warning regarding acceptable percent of timeout error requests for a storage" + default = 50 +} + +variable "network_error_requests_enabled" { + description = "Flag to enable Storage network errors monitor" + type = string + default = "true" +} + +variable "network_error_requests_extra_tags" { + description = "Extra tags for Storage network errors monitor" + type = list(string) + default = [] +} + +variable "network_error_requests_message" { + description = "Custom message for Storage network errors monitor" + type = string + default = "" +} + +variable "network_error_requests_time_aggregator" { + description = "Monitor aggregator for Storage network errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "network_error_requests_timeframe" { + description = "Monitor timeframe for Storage network errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "network_error_requests_threshold_critical" { + description = "Maximum acceptable percent of network error requests for a storage" + default = 90 +} + +variable "network_error_requests_threshold_warning" { + description = "Warning regarding acceptable percent of network error requests for a storage" + default = 50 +} + +variable "throttling_error_requests_enabled" { + description = "Flag to enable Storage throttling error monitor" + type = string + default = "true" +} + +variable "throttling_error_requests_extra_tags" { + description = "Extra tags for Storage throttling error monitor" + type = list(string) + default = [] +} + +variable "throttling_error_requests_message" { + description = "Custom message for Storage throttling error monitor" + type = string + default = "" +} + +variable "throttling_error_requests_time_aggregator" { + description = "Monitor aggregator for Storage throttling errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "throttling_error_requests_timeframe" { + description = "Monitor timeframe for Storage throttling errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "throttling_error_requests_threshold_critical" { + description = "Maximum acceptable percent of throttling error requests for a storage" + default = 90 +} + +variable "throttling_error_requests_threshold_warning" { + description = "Warning regarding acceptable percent of throttling error requests for a storage" + default = 50 +} + +variable "server_other_error_requests_enabled" { + description = "Flag to enable Storage server other errors monitor" + type = string + default = "true" +} + +variable "server_other_error_requests_extra_tags" { + description = "Extra tags for Storage server other errors monitor" + type = list(string) + default = [] +} + +variable "server_other_error_requests_message" { + description = "Custom message for Storage server other errors monitor" + type = string + default = "" +} + +variable "server_other_error_requests_time_aggregator" { + description = "Monitor aggregator for Storage other errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "server_other_error_requests_timeframe" { + description = "Monitor timeframe for Storage server other errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "server_other_error_requests_threshold_critical" { + description = "Maximum acceptable percent of server other error requests for a storage" + default = 90 +} + +variable "server_other_error_requests_threshold_warning" { + description = "Warning regarding acceptable percent of server other error requests for a storage" + default = 50 +} + +variable "client_other_error_requests_enabled" { + description = "Flag to enable Storage other errors monitor" + type = string + default = "true" +} + +variable "client_other_error_requests_extra_tags" { + description = "Extra tags for Storage other errors monitor" + type = list(string) + default = [] +} + +variable "client_other_error_requests_message" { + description = "Custom message for Storage other errors monitor" + type = string + default = "" +} + +variable "client_other_error_requests_time_aggregator" { + description = "Monitor aggregator for Storage other errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "client_other_error_requests_timeframe" { + description = "Monitor timeframe for Storage other errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "client_other_error_requests_threshold_critical" { + description = "Maximum acceptable percent of client other error requests for a storage" + default = 90 +} + +variable "client_other_error_requests_threshold_warning" { + description = "Warning regarding acceptable percent of client other error requests for a storage" + default = 50 +} + +variable "authorization_error_requests_enabled" { + description = "Flag to enable Storage authorization errors monitor" + type = string + default = "true" +} + +variable "authorization_error_requests_extra_tags" { + description = "Extra tags for Storage authorization errors monitor" + type = list(string) + default = [] +} + +variable "authorization_error_requests_message" { + description = "Custom message for Storage authorization errors monitor" + type = string + default = "" +} + +variable "authorization_error_requests_time_aggregator" { + description = "Monitor aggregator for Storage authorization errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "authorization_error_requests_timeframe" { + description = "Monitor timeframe for Storage authorization errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "authorization_error_requests_threshold_critical" { + description = "Maximum acceptable percent of authorization error requests for a storage" + default = 90 +} + +variable "authorization_error_requests_threshold_warning" { + description = "Warning regarding acceptable percent of authorization error requests for a storage" + default = 50 +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for Storage Services status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for Storage Services status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "status_enabled" { + description = "Flag to enable App Services status monitor" + type = string + default = "true" +} + +variable "status_message" { + description = "Custom message for storage Services status monitor" + type = string + default = "" +} + +variable "status_extra_tags" { + description = "Extra tags for App Services status monitor" + type = list(string) + default = [] +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/storage/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/storage/modules.tf new file mode 100755 index 0000000..db573ae --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/storage/modules.tf @@ -0,0 +1,123 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_storage" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = [] +} + +module "filter-tags-blob" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_storage" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = [] + extra_tags_excluded = ["apiname:getblobproperties", "apiname:createcontainer"] +} + +module "filter-tags-success" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_storage" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["responsetype:success"] +} + +module "filter-tags-success-blob" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_storage" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["responsetype:success"] + extra_tags_excluded = ["apiname:getblobproperties", "apiname:createcontainer"] +} + +module "filter-tags-timeout-error" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_storage" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["responsetype:servertimeouterror"] +} + +module "filter-tags-network-error" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_storage" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["responsetype:networkerror"] +} + +module "filter-tags-throttling-error" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_storage" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["responsetype:serverbusyerror"] +} + +module "filter-tags-server-other-error" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_storage" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["responsetype:serverothererror"] +} + +module "filter-tags-client-other-error" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_storage" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["responsetype:clientothererror"] +} + +module "filter-tags-client-other-error-blob" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_storage" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["responsetype:clientothererror"] + extra_tags_excluded = ["apiname:getblobproperties", "apiname:createcontainer"] +} + +module "filter-tags-authorization-error" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_storage" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["responsetype:authorizationerror"] +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/storage/monitors-azure-storage.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/storage/monitors-azure-storage.tf new file mode 100755 index 0000000..918ec7c --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/storage/monitors-azure-storage.tf @@ -0,0 +1,1044 @@ +resource "datadog_monitor" "storage_status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Storage is down" + message = coalesce(var.status_message, var.message) + + query = < ${var.successful_storage_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.successful_storage_requests_threshold_critical + warning = var.successful_storage_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.successful_requests_extra_tags) +} + +resource "datadog_monitor" "fileservices_requests_error" { + count = var.successful_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Storage File service too few successful requests {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.successful_requests_message, var.message) + query = < ${var.successful_storage_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.successful_storage_requests_threshold_critical + warning = var.successful_storage_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.successful_requests_extra_tags) +} + +resource "datadog_monitor" "queueservices_requests_error" { + count = var.successful_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Storage Queue service too few successful requests {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.successful_requests_message, var.message) + + query = < ${var.successful_storage_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.successful_storage_requests_threshold_critical + warning = var.successful_storage_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.successful_requests_extra_tags) +} + +resource "datadog_monitor" "tableservices_requests_error" { + count = var.successful_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Storage Table service too few successful requests {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.successful_requests_message, var.message) + + query = < ${var.successful_storage_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.successful_storage_requests_threshold_critical + warning = var.successful_storage_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.successful_requests_extra_tags) +} + +resource "datadog_monitor" "blobservices_latency" { + count = var.latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Storage Blob service too high end to end latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.latency_message, var.message) + + query = < ${var.latency_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.latency_threshold_critical + warning = var.latency_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.latency_extra_tags) +} + +resource "datadog_monitor" "fileservices_latency" { + count = var.latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Storage File service too high end to end latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.latency_message, var.message) + + query = < ${var.latency_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.latency_threshold_critical + warning = var.latency_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.latency_extra_tags) +} + +resource "datadog_monitor" "queueservices_latency" { + count = var.latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Storage Queue service too high end to end latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.latency_message, var.message) + + query = < ${var.latency_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.latency_threshold_critical + warning = var.latency_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.latency_extra_tags) +} + +resource "datadog_monitor" "tableservices_latency" { + count = var.latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Storage Table service too high end to end latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.latency_message, var.message) + + query = < ${var.latency_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.latency_threshold_critical + warning = var.latency_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.latency_extra_tags) +} + +resource "datadog_monitor" "blob_timeout_error_requests" { + count = var.timeout_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Blob Storage too many timeout errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.timeout_error_requests_message, var.message) + + query = < ${var.timeout_error_requests_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.timeout_error_requests_threshold_critical + warning = var.timeout_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.timeout_error_requests_extra_tags) +} + +resource "datadog_monitor" "file_timeout_error_requests" { + count = var.timeout_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure File Storage too many timeout errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.timeout_error_requests_message, var.message) + + query = < ${var.timeout_error_requests_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.timeout_error_requests_threshold_critical + warning = var.timeout_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.timeout_error_requests_extra_tags) +} + +resource "datadog_monitor" "queue_timeout_error_requests" { + count = var.timeout_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Queue Storage too many timeout errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.timeout_error_requests_message, var.message) + + query = < ${var.timeout_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.timeout_error_requests_threshold_critical + warning = var.timeout_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.timeout_error_requests_extra_tags) +} + +resource "datadog_monitor" "table_timeout_error_requests" { + count = var.timeout_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Table Storage too many timeout errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.timeout_error_requests_message, var.message) + + query = < ${var.timeout_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.timeout_error_requests_threshold_critical + warning = var.timeout_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.timeout_error_requests_extra_tags) +} + +resource "datadog_monitor" "blob_network_error_requests" { + count = var.network_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Blob Storage too many network errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.network_error_requests_message, var.message) + + query = < ${var.network_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.network_error_requests_threshold_critical + warning = var.network_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.network_error_requests_extra_tags) +} + +resource "datadog_monitor" "file_network_error_requests" { + count = var.network_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure File Storage too many network errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.network_error_requests_message, var.message) + + query = < ${var.network_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.network_error_requests_threshold_critical + warning = var.network_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.network_error_requests_extra_tags) +} + +resource "datadog_monitor" "queue_network_error_requests" { + count = var.network_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Queue Storage too many network errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.network_error_requests_message, var.message) + + query = < ${var.network_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.network_error_requests_threshold_critical + warning = var.network_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.network_error_requests_extra_tags) +} + +resource "datadog_monitor" "table_network_error_requests" { + count = var.network_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Table Storage too many network errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.network_error_requests_message, var.message) + + query = < ${var.network_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.network_error_requests_threshold_critical + warning = var.network_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.network_error_requests_extra_tags) +} + +resource "datadog_monitor" "blob_throttling_error_requests" { + count = var.throttling_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Blob Storage too many throttling errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.throttling_error_requests_message, var.message) + + query = < ${var.throttling_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.throttling_error_requests_threshold_critical + warning = var.throttling_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.throttling_error_requests_extra_tags) +} + +resource "datadog_monitor" "file_throttling_error_requests" { + count = var.throttling_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure File Storage too many throttling errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.throttling_error_requests_message, var.message) + + query = < ${var.throttling_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.throttling_error_requests_threshold_critical + warning = var.throttling_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.throttling_error_requests_extra_tags) +} + +resource "datadog_monitor" "queue_throttling_error_requests" { + count = var.throttling_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Queue Storage too many throttling errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.throttling_error_requests_message, var.message) + + query = < ${var.throttling_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.throttling_error_requests_threshold_critical + warning = var.throttling_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.throttling_error_requests_extra_tags) +} + +resource "datadog_monitor" "table_throttling_error_requests" { + count = var.throttling_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Table Storage too many throttling errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.throttling_error_requests_message, var.message) + + query = < ${var.throttling_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.throttling_error_requests_threshold_critical + warning = var.throttling_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.throttling_error_requests_extra_tags) +} + +resource "datadog_monitor" "blob_server_other_error_requests" { + count = var.server_other_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Blob Storage too many server_other errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.server_other_error_requests_message, var.message) + + query = < ${var.server_other_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.server_other_error_requests_threshold_critical + warning = var.server_other_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.server_other_error_requests_extra_tags) +} + +resource "datadog_monitor" "file_server_other_error_requests" { + count = var.server_other_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure File Storage too many server_other errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.server_other_error_requests_message, var.message) + + query = < ${var.server_other_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.server_other_error_requests_threshold_critical + warning = var.server_other_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.server_other_error_requests_extra_tags) +} + +resource "datadog_monitor" "queue_server_other_error_requests" { + count = var.server_other_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Queue Storage too many server_other errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.server_other_error_requests_message, var.message) + + query = < ${var.server_other_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.server_other_error_requests_threshold_critical + warning = var.server_other_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.server_other_error_requests_extra_tags) +} + +resource "datadog_monitor" "table_server_other_error_requests" { + count = var.server_other_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Table Storage too many server_other errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.server_other_error_requests_message, var.message) + + query = < ${var.server_other_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.server_other_error_requests_threshold_critical + warning = var.server_other_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.server_other_error_requests_extra_tags) +} + +resource "datadog_monitor" "blob_client_other_error_requests" { + count = var.client_other_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Blob Storage too many client_other errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.client_other_error_requests_message, var.message) + query = < ${var.client_other_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.client_other_error_requests_threshold_critical + warning = var.client_other_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.client_other_error_requests_extra_tags) +} + +resource "datadog_monitor" "file_client_other_error_requests" { + count = var.client_other_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure File Storage too many client_other errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.client_other_error_requests_message, var.message) + + query = < ${var.client_other_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.client_other_error_requests_threshold_critical + warning = var.client_other_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.client_other_error_requests_extra_tags) +} + +resource "datadog_monitor" "queue_client_other_error_requests" { + count = var.client_other_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Queue Storage too many client_other errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.client_other_error_requests_message, var.message) + + query = < ${var.client_other_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.client_other_error_requests_threshold_critical + warning = var.client_other_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.client_other_error_requests_extra_tags) +} + +resource "datadog_monitor" "table_client_other_error_requests" { + count = var.client_other_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Table Storage too many client_other errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.client_other_error_requests_message, var.message) + + query = < ${var.client_other_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.client_other_error_requests_threshold_critical + warning = var.client_other_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.client_other_error_requests_extra_tags) +} + +resource "datadog_monitor" "blob_authorization_error_requests" { + count = var.authorization_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Blob Storage too many authorization errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.authorization_error_requests_message, var.message) + + query = < ${var.authorization_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.authorization_error_requests_threshold_critical + warning = var.authorization_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.authorization_error_requests_extra_tags) +} + +resource "datadog_monitor" "file_authorization_error_requests" { + count = var.authorization_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure File Storage too many authorization errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.authorization_error_requests_message, var.message) + + query = < ${var.authorization_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.authorization_error_requests_threshold_critical + warning = var.authorization_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.authorization_error_requests_extra_tags) +} + +resource "datadog_monitor" "queue_authorization_error_requests" { + count = var.authorization_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Queue Storage too many authorization errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.authorization_error_requests_message, var.message) + + query = < ${var.authorization_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.authorization_error_requests_threshold_critical + warning = var.authorization_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.authorization_error_requests_extra_tags) +} + +resource "datadog_monitor" "table_authorization_error_requests" { + count = var.authorization_error_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Azure Table Storage too many authorization errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.authorization_error_requests_message, var.message) + + query = < ${var.authorization_error_requests_threshold_critical} +EOQ + + + monitor_thresholds { + critical = var.authorization_error_requests_threshold_critical + warning = var.authorization_error_requests_threshold_warning + } + + type = "metric alert" + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + new_host_delay = var.new_host_delay + evaluation_delay = var.evaluation_delay + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:storage", "team:claranet", "created-by:terraform"], var.authorization_error_requests_extra_tags) +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/storage/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/storage/outputs.tf new file mode 100755 index 0000000..9edd5e0 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/storage/outputs.tf @@ -0,0 +1,165 @@ +output "blob_authorization_error_requests_id" { + description = "id for monitor blob_authorization_error_requests" + value = datadog_monitor.blob_authorization_error_requests.*.id +} + +output "blob_client_other_error_requests_id" { + description = "id for monitor blob_client_other_error_requests" + value = datadog_monitor.blob_client_other_error_requests.*.id +} + +output "blob_network_error_requests_id" { + description = "id for monitor blob_network_error_requests" + value = datadog_monitor.blob_network_error_requests.*.id +} + +output "blob_server_other_error_requests_id" { + description = "id for monitor blob_server_other_error_requests" + value = datadog_monitor.blob_server_other_error_requests.*.id +} + +output "blob_throttling_error_requests_id" { + description = "id for monitor blob_throttling_error_requests" + value = datadog_monitor.blob_throttling_error_requests.*.id +} + +output "blob_timeout_error_requests_id" { + description = "id for monitor blob_timeout_error_requests" + value = datadog_monitor.blob_timeout_error_requests.*.id +} + +output "blobservices_latency_id" { + description = "id for monitor blobservices_latency" + value = datadog_monitor.blobservices_latency.*.id +} + +output "blobservices_requests_error_id" { + description = "id for monitor blobservices_requests_error" + value = datadog_monitor.blobservices_requests_error.*.id +} + +output "file_authorization_error_requests_id" { + description = "id for monitor file_authorization_error_requests" + value = datadog_monitor.file_authorization_error_requests.*.id +} + +output "file_client_other_error_requests_id" { + description = "id for monitor file_client_other_error_requests" + value = datadog_monitor.file_client_other_error_requests.*.id +} + +output "file_network_error_requests_id" { + description = "id for monitor file_network_error_requests" + value = datadog_monitor.file_network_error_requests.*.id +} + +output "file_server_other_error_requests_id" { + description = "id for monitor file_server_other_error_requests" + value = datadog_monitor.file_server_other_error_requests.*.id +} + +output "file_throttling_error_requests_id" { + description = "id for monitor file_throttling_error_requests" + value = datadog_monitor.file_throttling_error_requests.*.id +} + +output "file_timeout_error_requests_id" { + description = "id for monitor file_timeout_error_requests" + value = datadog_monitor.file_timeout_error_requests.*.id +} + +output "fileservices_latency_id" { + description = "id for monitor fileservices_latency" + value = datadog_monitor.fileservices_latency.*.id +} + +output "fileservices_requests_error_id" { + description = "id for monitor fileservices_requests_error" + value = datadog_monitor.fileservices_requests_error.*.id +} + +output "queue_authorization_error_requests_id" { + description = "id for monitor queue_authorization_error_requests" + value = datadog_monitor.queue_authorization_error_requests.*.id +} + +output "queue_client_other_error_requests_id" { + description = "id for monitor queue_client_other_error_requests" + value = datadog_monitor.queue_client_other_error_requests.*.id +} + +output "queue_network_error_requests_id" { + description = "id for monitor queue_network_error_requests" + value = datadog_monitor.queue_network_error_requests.*.id +} + +output "queue_server_other_error_requests_id" { + description = "id for monitor queue_server_other_error_requests" + value = datadog_monitor.queue_server_other_error_requests.*.id +} + +output "queue_throttling_error_requests_id" { + description = "id for monitor queue_throttling_error_requests" + value = datadog_monitor.queue_throttling_error_requests.*.id +} + +output "queue_timeout_error_requests_id" { + description = "id for monitor queue_timeout_error_requests" + value = datadog_monitor.queue_timeout_error_requests.*.id +} + +output "queueservices_latency_id" { + description = "id for monitor queueservices_latency" + value = datadog_monitor.queueservices_latency.*.id +} + +output "queueservices_requests_error_id" { + description = "id for monitor queueservices_requests_error" + value = datadog_monitor.queueservices_requests_error.*.id +} + +output "storage_status_id" { + description = "id for monitor storage_status" + value = datadog_monitor.storage_status.*.id +} + +output "table_authorization_error_requests_id" { + description = "id for monitor table_authorization_error_requests" + value = datadog_monitor.table_authorization_error_requests.*.id +} + +output "table_client_other_error_requests_id" { + description = "id for monitor table_client_other_error_requests" + value = datadog_monitor.table_client_other_error_requests.*.id +} + +output "table_network_error_requests_id" { + description = "id for monitor table_network_error_requests" + value = datadog_monitor.table_network_error_requests.*.id +} + +output "table_server_other_error_requests_id" { + description = "id for monitor table_server_other_error_requests" + value = datadog_monitor.table_server_other_error_requests.*.id +} + +output "table_throttling_error_requests_id" { + description = "id for monitor table_throttling_error_requests" + value = datadog_monitor.table_throttling_error_requests.*.id +} + +output "table_timeout_error_requests_id" { + description = "id for monitor table_timeout_error_requests" + value = datadog_monitor.table_timeout_error_requests.*.id +} + +output "tableservices_latency_id" { + description = "id for monitor tableservices_latency" + value = datadog_monitor.tableservices_latency.*.id +} + +output "tableservices_requests_error_id" { + description = "id for monitor tableservices_requests_error" + value = datadog_monitor.tableservices_requests_error.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/storage/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/storage/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/storage/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/stream-analytics/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/stream-analytics/README.md new file mode 100755 index 0000000..729cfb8 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/stream-analytics/README.md @@ -0,0 +1,114 @@ +# CLOUD AZURE STREAM-ANALYTICS DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-stream-analytics" { + source = "claranet/monitors/datadog//cloud/azure/stream-analytics" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Stream Analytics is down +- Stream Analytics streaming units utilization too high +- Stream Analytics too many conversion errors +- Stream Analytics too many failed requests +- Stream Analytics too many runtime errors + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.conversion_errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.failed_function_requests](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.runtime_errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.su_utilization](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [conversion\_errors\_enabled](#input\_conversion\_errors\_enabled) | Flag to enable Stream Analytics conversion errors monitor | `string` | `"true"` | no | +| [conversion\_errors\_extra\_tags](#input\_conversion\_errors\_extra\_tags) | Extra tags for Stream Analytics conversion errors monitor | `list(string)` | `[]` | no | +| [conversion\_errors\_message](#input\_conversion\_errors\_message) | Custom message for Stream Analytics conversion errors monitor | `string` | `""` | no | +| [conversion\_errors\_threshold\_critical](#input\_conversion\_errors\_threshold\_critical) | Conversion errors limit (critical threshold) | `number` | `10` | no | +| [conversion\_errors\_threshold\_warning](#input\_conversion\_errors\_threshold\_warning) | Conversion errors limit (warning threshold) | `number` | `0` | no | +| [conversion\_errors\_time\_aggregator](#input\_conversion\_errors\_time\_aggregator) | Monitor aggregator for Stream Analytics conversion errors [available values: min, max or avg] | `string` | `"min"` | no | +| [conversion\_errors\_timeframe](#input\_conversion\_errors\_timeframe) | Monitor timeframe for Stream Analytics conversion errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [failed\_function\_requests\_enabled](#input\_failed\_function\_requests\_enabled) | Flag to enable Stream Analytics failed requests monitor | `string` | `"true"` | no | +| [failed\_function\_requests\_extra\_tags](#input\_failed\_function\_requests\_extra\_tags) | Extra tags for Stream Analytics failed requests monitor | `list(string)` | `[]` | no | +| [failed\_function\_requests\_message](#input\_failed\_function\_requests\_message) | Custom message for Stream Analytics failed requests monitor | `string` | `""` | no | +| [failed\_function\_requests\_threshold\_critical](#input\_failed\_function\_requests\_threshold\_critical) | Failed Function Request rate limit (critical threshold) | `number` | `10` | no | +| [failed\_function\_requests\_threshold\_warning](#input\_failed\_function\_requests\_threshold\_warning) | Failed Function Request rate limit (warning threshold) | `number` | `0` | no | +| [failed\_function\_requests\_time\_aggregator](#input\_failed\_function\_requests\_time\_aggregator) | Monitor aggregator for Stream Analytics failed requests [available values: min, max or avg] | `string` | `"min"` | no | +| [failed\_function\_requests\_timeframe](#input\_failed\_function\_requests\_timeframe) | Monitor timeframe for Stream Analytics failed requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a Redis monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [runtime\_errors\_enabled](#input\_runtime\_errors\_enabled) | Flag to enable Stream Analytics runtime errors monitor | `string` | `"true"` | no | +| [runtime\_errors\_extra\_tags](#input\_runtime\_errors\_extra\_tags) | Extra tags for Stream Analytics runtime errors monitor | `list(string)` | `[]` | no | +| [runtime\_errors\_message](#input\_runtime\_errors\_message) | Custom message for Stream Analytics runtime errors monitor | `string` | `""` | no | +| [runtime\_errors\_threshold\_critical](#input\_runtime\_errors\_threshold\_critical) | Runtime errors limit (critical threshold) | `number` | `10` | no | +| [runtime\_errors\_threshold\_warning](#input\_runtime\_errors\_threshold\_warning) | Runtime errors limit (warning threshold) | `number` | `0` | no | +| [runtime\_errors\_time\_aggregator](#input\_runtime\_errors\_time\_aggregator) | Monitor aggregator for Stream Analytics runtime errors [available values: min, max or avg] | `string` | `"min"` | no | +| [runtime\_errors\_timeframe](#input\_runtime\_errors\_timeframe) | Monitor timeframe for Stream Analytics runtime errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable Stream Analytics status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for Stream Analytics status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for Stream Analytics status monitor | `string` | `""` | no | +| [status\_no\_data\_timeframe](#input\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for Stream Analytics status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for Stream Analytics status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [su\_utilization\_enabled](#input\_su\_utilization\_enabled) | Flag to enable Stream Analytics utilization monitor | `string` | `"true"` | no | +| [su\_utilization\_extra\_tags](#input\_su\_utilization\_extra\_tags) | Extra tags for Stream Analytics utilization monitor | `list(string)` | `[]` | no | +| [su\_utilization\_message](#input\_su\_utilization\_message) | Custom message for Stream Analytics utilization monitor | `string` | `""` | no | +| [su\_utilization\_threshold\_critical](#input\_su\_utilization\_threshold\_critical) | Streaming Unit utilization rate limit (critical threshold) | `number` | `95` | no | +| [su\_utilization\_threshold\_warning](#input\_su\_utilization\_threshold\_warning) | Streaming Unit utilization rate limit (warning threshold) | `number` | `80` | no | +| [su\_utilization\_time\_aggregator](#input\_su\_utilization\_time\_aggregator) | Monitor aggregator for Stream Analytics utilization [available values: min, max or avg] | `string` | `"min"` | no | +| [su\_utilization\_timeframe](#input\_su\_utilization\_timeframe) | Monitor timeframe for Stream Analytics utilization [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [conversion\_errors\_id](#output\_conversion\_errors\_id) | id for monitor conversion\_errors | +| [failed\_function\_requests\_id](#output\_failed\_function\_requests\_id) | id for monitor failed\_function\_requests | +| [runtime\_errors\_id](#output\_runtime\_errors\_id) | id for monitor runtime\_errors | +| [status\_id](#output\_status\_id) | id for monitor status | +| [su\_utilization\_id](#output\_su\_utilization\_id) | id for monitor su\_utilization | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure/](https://docs.datadoghq.com/integrations/azure/) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/stream-analytics/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/stream-analytics/inputs.tf new file mode 100755 index 0000000..fd4ba71 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/stream-analytics/inputs.tf @@ -0,0 +1,244 @@ +# Global Terraform +variable "environment" { + description = "Architecture environment" + type = string +} + +# Global DataDog +variable "message" { + description = "Message sent when a Redis monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Azure Stream Analytics specific variables + +variable "status_enabled" { + description = "Flag to enable Stream Analytics status monitor" + type = string + default = "true" +} + +variable "status_extra_tags" { + description = "Extra tags for Stream Analytics status monitor" + type = list(string) + default = [] +} + +variable "status_message" { + description = "Custom message for Stream Analytics status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for Stream Analytics status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for Stream Analytics status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "su_utilization_enabled" { + description = "Flag to enable Stream Analytics utilization monitor" + type = string + default = "true" +} + +variable "su_utilization_extra_tags" { + description = "Extra tags for Stream Analytics utilization monitor" + type = list(string) + default = [] +} + +variable "su_utilization_message" { + description = "Custom message for Stream Analytics utilization monitor" + type = string + default = "" +} + +variable "su_utilization_time_aggregator" { + description = "Monitor aggregator for Stream Analytics utilization [available values: min, max or avg]" + type = string + default = "min" +} + +variable "su_utilization_timeframe" { + description = "Monitor timeframe for Stream Analytics utilization [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "su_utilization_threshold_warning" { + description = "Streaming Unit utilization rate limit (warning threshold)" + default = 80 +} + +variable "su_utilization_threshold_critical" { + description = "Streaming Unit utilization rate limit (critical threshold)" + default = 95 +} + +variable "failed_function_requests_enabled" { + description = "Flag to enable Stream Analytics failed requests monitor" + type = string + default = "true" +} + +variable "failed_function_requests_extra_tags" { + description = "Extra tags for Stream Analytics failed requests monitor" + type = list(string) + default = [] +} + +variable "failed_function_requests_message" { + description = "Custom message for Stream Analytics failed requests monitor" + type = string + default = "" +} + +variable "failed_function_requests_time_aggregator" { + description = "Monitor aggregator for Stream Analytics failed requests [available values: min, max or avg]" + type = string + default = "min" +} + +variable "failed_function_requests_timeframe" { + description = "Monitor timeframe for Stream Analytics failed requests [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "failed_function_requests_threshold_warning" { + description = "Failed Function Request rate limit (warning threshold)" + default = 0 +} + +variable "failed_function_requests_threshold_critical" { + description = "Failed Function Request rate limit (critical threshold)" + default = 10 +} + +variable "conversion_errors_enabled" { + description = "Flag to enable Stream Analytics conversion errors monitor" + type = string + default = "true" +} + +variable "conversion_errors_extra_tags" { + description = "Extra tags for Stream Analytics conversion errors monitor" + type = list(string) + default = [] +} + +variable "conversion_errors_message" { + description = "Custom message for Stream Analytics conversion errors monitor" + type = string + default = "" +} + +variable "conversion_errors_time_aggregator" { + description = "Monitor aggregator for Stream Analytics conversion errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "conversion_errors_timeframe" { + description = "Monitor timeframe for Stream Analytics conversion errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "conversion_errors_threshold_warning" { + description = "Conversion errors limit (warning threshold)" + default = 0 +} + +variable "conversion_errors_threshold_critical" { + description = "Conversion errors limit (critical threshold)" + default = 10 +} + +variable "runtime_errors_enabled" { + description = "Flag to enable Stream Analytics runtime errors monitor" + type = string + default = "true" +} + +variable "runtime_errors_extra_tags" { + description = "Extra tags for Stream Analytics runtime errors monitor" + type = list(string) + default = [] +} + +variable "runtime_errors_message" { + description = "Custom message for Stream Analytics runtime errors monitor" + type = string + default = "" +} + +variable "runtime_errors_time_aggregator" { + description = "Monitor aggregator for Stream Analytics runtime errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "runtime_errors_timeframe" { + description = "Monitor timeframe for Stream Analytics runtime errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "runtime_errors_threshold_warning" { + description = "Runtime errors limit (warning threshold)" + default = 0 +} + +variable "runtime_errors_threshold_critical" { + description = "Runtime errors limit (critical threshold)" + default = 10 +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/stream-analytics/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/stream-analytics/modules.tf new file mode 100755 index 0000000..868c6a9 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/stream-analytics/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_stream-analytics" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/stream-analytics/monitors-stream-analytics.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/stream-analytics/monitors-stream-analytics.tf new file mode 100755 index 0000000..d7f30ca --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/stream-analytics/monitors-stream-analytics.tf @@ -0,0 +1,147 @@ +resource "datadog_monitor" "status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Stream Analytics is down" + message = coalesce(var.status_message, var.message) + type = "query alert" + + query = < ${var.su_utilization_threshold_critical} +EOQ + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + monitor_thresholds { + warning = var.su_utilization_threshold_warning + critical = var.su_utilization_threshold_critical + } + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:stream-analytics", "team:claranet", "created-by:terraform"], var.su_utilization_extra_tags) +} + +resource "datadog_monitor" "failed_function_requests" { + count = var.failed_function_requests_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Stream Analytics too many failed requests {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.failed_function_requests_message, var.message) + type = "query alert" + + query = < ${var.failed_function_requests_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.failed_function_requests_threshold_warning + critical = var.failed_function_requests_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 60 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:stream-analytics", "team:claranet", "created-by:terraform"], var.failed_function_requests_extra_tags) +} + +resource "datadog_monitor" "conversion_errors" { + count = var.conversion_errors_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Stream Analytics too many conversion errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.conversion_errors_message, var.message) + type = "query alert" + + query = < ${var.conversion_errors_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.conversion_errors_threshold_warning + critical = var.conversion_errors_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:stream-analytics", "team:claranet", "created-by:terraform"], var.conversion_errors_extra_tags) +} + +resource "datadog_monitor" "runtime_errors" { + count = var.runtime_errors_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Stream Analytics too many runtime errors {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.runtime_errors_message, var.message) + type = "query alert" + + query = < ${var.runtime_errors_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.runtime_errors_threshold_warning + critical = var.runtime_errors_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:stream-analytics", "team:claranet", "created-by:terraform"], var.runtime_errors_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/stream-analytics/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/stream-analytics/outputs.tf new file mode 100755 index 0000000..c9ac170 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/stream-analytics/outputs.tf @@ -0,0 +1,25 @@ +output "conversion_errors_id" { + description = "id for monitor conversion_errors" + value = datadog_monitor.conversion_errors.*.id +} + +output "failed_function_requests_id" { + description = "id for monitor failed_function_requests" + value = datadog_monitor.failed_function_requests.*.id +} + +output "runtime_errors_id" { + description = "id for monitor runtime_errors" + value = datadog_monitor.runtime_errors.*.id +} + +output "status_id" { + description = "id for monitor status" + value = datadog_monitor.status.*.id +} + +output "su_utilization_id" { + description = "id for monitor su_utilization" + value = datadog_monitor.su_utilization.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/stream-analytics/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/stream-analytics/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/stream-analytics/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/virtual-machine/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/virtual-machine/README.md new file mode 100755 index 0000000..611e53f --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/virtual-machine/README.md @@ -0,0 +1,124 @@ +# CLOUD AZURE VIRTUAL-MACHINE DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-azure-virtual-machine" { + source = "claranet/monitors/datadog//cloud/azure/virtual-machine" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Virtual Machine CPU usage +- Virtual Machine credit CPU +- Virtual Machine disk space +- Virtual Machine is unreachable +- Virtual Machine RAM reserved +- Virtual Machine requests failed + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.virtualmachine_cpu_usage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.virtualmachine_credit_cpu_remaining_too_low](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.virtualmachine_disk_space](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.virtualmachine_ram_reserved](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.virtualmachine_requests_failed](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.virtualmachine_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_remaining\_rate\_enabled](#input\_cpu\_remaining\_rate\_enabled) | Flag to enable Virtual Machine CPU remaining monitor | `string` | `"true"` | no | +| [cpu\_remaining\_rate\_extra\_tags](#input\_cpu\_remaining\_rate\_extra\_tags) | Extra tags for Virtual Machine CPU remaining monitor | `list(string)` | `[]` | no | +| [cpu\_remaining\_rate\_message](#input\_cpu\_remaining\_rate\_message) | Custom message for Virtual Machine CPU remaining monitor | `string` | `""` | no | +| [cpu\_remaining\_rate\_threshold\_critical](#input\_cpu\_remaining\_rate\_threshold\_critical) | Virtual Machine CPU rate limit (critical threshold) | `number` | `15` | no | +| [cpu\_remaining\_rate\_threshold\_warning](#input\_cpu\_remaining\_rate\_threshold\_warning) | Virtual Machine CPU rate limit (warning threshold) | `number` | `30` | no | +| [cpu\_remaining\_rate\_time\_aggregator](#input\_cpu\_remaining\_rate\_time\_aggregator) | Monitor aggregator for Virtual Machine CPU remaining [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [cpu\_remaining\_rate\_timeframe](#input\_cpu\_remaining\_rate\_timeframe) | Monitor timeframe for Virtual Machine CPU remaining [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [cpu\_usage\_enabled](#input\_cpu\_usage\_enabled) | Flag to enable Virtual Machine status monitor | `string` | `"true"` | no | +| [cpu\_usage\_extra\_tags](#input\_cpu\_usage\_extra\_tags) | Extra tags for Virtual Machine status monitor | `list(string)` | `[]` | no | +| [cpu\_usage\_message](#input\_cpu\_usage\_message) | Custom message for Virtual Machine CPU monitor | `string` | `""` | no | +| [cpu\_usage\_threshold\_critical](#input\_cpu\_usage\_threshold\_critical) | Virtual Machine CPU usage in percent (critical threshold) | `string` | `"90"` | no | +| [cpu\_usage\_threshold\_warning](#input\_cpu\_usage\_threshold\_warning) | Virtual Machine CPU usage in percent (warning threshold) | `string` | `"80"` | no | +| [cpu\_usage\_time\_aggregator](#input\_cpu\_usage\_time\_aggregator) | Monitor aggregator for Virtual Machine CPU [available values: min, max or avg] | `string` | `"min"` | no | +| [cpu\_usage\_timeframe](#input\_cpu\_usage\_timeframe) | Monitor timeframe for Virtual Machine CPU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [disk\_space\_enabled](#input\_disk\_space\_enabled) | Flag to enable Virtual Machine status monitor | `string` | `"true"` | no | +| [disk\_space\_extra\_tags](#input\_disk\_space\_extra\_tags) | Extra tags for Virtual Machine free disk space monitor | `list(string)` | `[]` | no | +| [disk\_space\_message](#input\_disk\_space\_message) | Custom message for Virtual Machine CPU free disk space monitor | `string` | `""` | no | +| [disk\_space\_threshold\_critical](#input\_disk\_space\_threshold\_critical) | Virtual Machine free disk space in percent (critical threshold) | `string` | `"95"` | no | +| [disk\_space\_threshold\_warning](#input\_disk\_space\_threshold\_warning) | Virtual Machine free disk space in percent (warning threshold) | `string` | `"90"` | no | +| [disk\_space\_time\_aggregator](#input\_disk\_space\_time\_aggregator) | Monitor aggregator for Virtual Machine free disk space [available values: min, max or avg] | `string` | `"max"` | no | +| [disk\_space\_timeframe](#input\_disk\_space\_timeframe) | Monitor timeframe for Virtual Machine free disk space too low [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a Redis monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [ram\_reserved\_enabled](#input\_ram\_reserved\_enabled) | Flag to enable Virtual Machine RAM reserved monitor | `string` | `"true"` | no | +| [ram\_reserved\_extra\_tags](#input\_ram\_reserved\_extra\_tags) | Extra tags for Virtual Machine RAM reserved monitor | `list(string)` | `[]` | no | +| [ram\_reserved\_message](#input\_ram\_reserved\_message) | Custom message for Virtual Machine RAM reserved monitor | `string` | `""` | no | +| [ram\_reserved\_threshold\_critical](#input\_ram\_reserved\_threshold\_critical) | Virtual Machine RAM reserved limit (critical threshold) | `number` | `95` | no | +| [ram\_reserved\_threshold\_warning](#input\_ram\_reserved\_threshold\_warning) | Virtual Machine RAM reserved limit (warning threshold) | `number` | `90` | no | +| [ram\_reserved\_time\_aggregator](#input\_ram\_reserved\_time\_aggregator) | Monitor aggregator for Virtual Machine RAM reserved [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [ram\_reserved\_timeframe](#input\_ram\_reserved\_timeframe) | Monitor timeframe for Virtual Machine RAM reserved [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [requests\_failed\_enabled](#input\_requests\_failed\_enabled) | Flag to enable Virtual Machine requests failed monitor | `string` | `"true"` | no | +| [requests\_failed\_extra\_tags](#input\_requests\_failed\_extra\_tags) | Extra tags for Virtual Machine requests failed monitor | `list(string)` | `[]` | no | +| [requests\_failed\_message](#input\_requests\_failed\_message) | Custom message for Virtual Machine requests failed monitor | `string` | `""` | no | +| [requests\_failed\_threshold\_critical](#input\_requests\_failed\_threshold\_critical) | Virtual Machine requests failed limit (critical threshold) | `number` | `95` | no | +| [requests\_failed\_threshold\_warning](#input\_requests\_failed\_threshold\_warning) | Virtual Machine requests failed limit (warning threshold) | `number` | `90` | no | +| [requests\_failed\_time\_aggregator](#input\_requests\_failed\_time\_aggregator) | Monitor aggregator for Virtual Machine requests failed [available values: min, max, sum or avg] | `string` | `"min"` | no | +| [requests\_failed\_timeframe](#input\_requests\_failed\_timeframe) | Monitor timeframe for Virtual Machine requests failed [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_10m"` | no | +| [status\_enabled](#input\_status\_enabled) | Flag to enable Virtual Machine status monitor | `string` | `"true"` | no | +| [status\_extra\_tags](#input\_status\_extra\_tags) | Extra tags for Virtual Machine status monitor | `list(string)` | `[]` | no | +| [status\_message](#input\_status\_message) | Custom message for Virtual Machine status monitor | `string` | `""` | no | +| [status\_time\_aggregator](#input\_status\_time\_aggregator) | Monitor aggregator for Virtual Machine status [available values: min, max or avg] | `string` | `"max"` | no | +| [status\_timeframe](#input\_status\_timeframe) | Monitor timeframe for Virtual Machine status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [virtualmachine\_status\_no\_data\_timeframe](#input\_virtualmachine\_status\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [virtualmachine\_cpu\_usage\_id](#output\_virtualmachine\_cpu\_usage\_id) | id for monitor virtualmachine\_cpu\_usage | +| [virtualmachine\_credit\_cpu\_remaining\_too\_low\_id](#output\_virtualmachine\_credit\_cpu\_remaining\_too\_low\_id) | id for monitor virtualmachine\_credit\_cpu\_remaining\_too\_low | +| [virtualmachine\_disk\_space\_id](#output\_virtualmachine\_disk\_space\_id) | id for monitor virtualmachine\_disk\_space | +| [virtualmachine\_ram\_reserved\_id](#output\_virtualmachine\_ram\_reserved\_id) | id for monitor virtualmachine\_ram\_reserved | +| [virtualmachine\_requests\_failed\_id](#output\_virtualmachine\_requests\_failed\_id) | id for monitor virtualmachine\_requests\_failed | +| [virtualmachine\_status\_id](#output\_virtualmachine\_status\_id) | id for monitor virtualmachine\_status | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/azure_vm/](https://docs.datadoghq.com/integrations/azure_vm/) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/virtual-machine/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/virtual-machine/inputs.tf new file mode 100755 index 0000000..336e341 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/virtual-machine/inputs.tf @@ -0,0 +1,283 @@ +# Global Terraform +variable "environment" { + description = "Architecture environment" + type = string +} + +# Global DataDog +variable "message" { + description = "Message sent when a Redis monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "virtualmachine_status_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Azure Virtual Machine specific variables + +variable "status_enabled" { + description = "Flag to enable Virtual Machine status monitor" + type = string + default = "true" +} + +variable "status_extra_tags" { + description = "Extra tags for Virtual Machine status monitor" + type = list(string) + default = [] +} + +variable "status_message" { + description = "Custom message for Virtual Machine status monitor" + type = string + default = "" +} + +variable "status_time_aggregator" { + description = "Monitor aggregator for Virtual Machine status [available values: min, max or avg]" + type = string + default = "max" +} + +variable "status_timeframe" { + description = "Monitor timeframe for Virtual Machine status [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "cpu_usage_enabled" { + description = "Flag to enable Virtual Machine status monitor" + type = string + default = "true" +} + +variable "cpu_usage_extra_tags" { + description = "Extra tags for Virtual Machine status monitor" + type = list(string) + default = [] +} + +variable "cpu_usage_message" { + description = "Custom message for Virtual Machine CPU monitor" + type = string + default = "" +} + +variable "cpu_usage_time_aggregator" { + description = "Monitor aggregator for Virtual Machine CPU [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cpu_usage_timeframe" { + description = "Monitor timeframe for Virtual Machine CPU [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "cpu_usage_threshold_warning" { + description = "Virtual Machine CPU usage in percent (warning threshold)" + default = "80" +} + +variable "cpu_usage_threshold_critical" { + description = "Virtual Machine CPU usage in percent (critical threshold)" + default = "90" +} + +variable "cpu_remaining_rate_enabled" { + description = "Flag to enable Virtual Machine CPU remaining monitor" + type = string + default = "true" +} + +variable "cpu_remaining_rate_extra_tags" { + description = "Extra tags for Virtual Machine CPU remaining monitor" + type = list(string) + default = [] +} + +variable "cpu_remaining_rate_message" { + description = "Custom message for Virtual Machine CPU remaining monitor" + type = string + default = "" +} + +variable "cpu_remaining_rate_time_aggregator" { + description = "Monitor aggregator for Virtual Machine CPU remaining [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "cpu_remaining_rate_timeframe" { + description = "Monitor timeframe for Virtual Machine CPU remaining [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "cpu_remaining_rate_threshold_warning" { + description = "Virtual Machine CPU rate limit (warning threshold)" + default = 30 +} + +variable "cpu_remaining_rate_threshold_critical" { + description = "Virtual Machine CPU rate limit (critical threshold)" + default = 15 +} + +variable "ram_reserved_enabled" { + description = "Flag to enable Virtual Machine RAM reserved monitor" + type = string + default = "true" +} + +variable "ram_reserved_message" { + description = "Custom message for Virtual Machine RAM reserved monitor" + type = string + default = "" +} + +variable "ram_reserved_extra_tags" { + description = "Extra tags for Virtual Machine RAM reserved monitor" + type = list(string) + default = [] +} + +variable "ram_reserved_time_aggregator" { + description = "Monitor aggregator for Virtual Machine RAM reserved [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "ram_reserved_timeframe" { + description = "Monitor timeframe for Virtual Machine RAM reserved [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "ram_reserved_threshold_warning" { + description = "Virtual Machine RAM reserved limit (warning threshold)" + default = 90 +} + +variable "ram_reserved_threshold_critical" { + description = "Virtual Machine RAM reserved limit (critical threshold)" + default = 95 +} + +variable "disk_space_enabled" { + description = "Flag to enable Virtual Machine status monitor" + type = string + default = "true" +} + +variable "disk_space_time_aggregator" { + description = "Monitor aggregator for Virtual Machine free disk space [available values: min, max or avg]" + type = string + default = "max" +} + +variable "disk_space_timeframe" { + description = "Monitor timeframe for Virtual Machine free disk space too low [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "disk_space_threshold_critical" { + description = "Virtual Machine free disk space in percent (critical threshold)" + default = "95" +} + +variable "disk_space_threshold_warning" { + description = "Virtual Machine free disk space in percent (warning threshold)" + default = "90" +} + +variable "disk_space_extra_tags" { + description = "Extra tags for Virtual Machine free disk space monitor" + type = list(string) + default = [] +} + +variable "disk_space_message" { + description = "Custom message for Virtual Machine CPU free disk space monitor" + type = string + default = "" +} + +variable "requests_failed_enabled" { + description = "Flag to enable Virtual Machine requests failed monitor" + type = string + default = "true" +} + +variable "requests_failed_message" { + description = "Custom message for Virtual Machine requests failed monitor" + type = string + default = "" +} + +variable "requests_failed_extra_tags" { + description = "Extra tags for Virtual Machine requests failed monitor" + type = list(string) + default = [] +} + +variable "requests_failed_time_aggregator" { + description = "Monitor aggregator for Virtual Machine requests failed [available values: min, max, sum or avg]" + type = string + default = "min" +} + +variable "requests_failed_timeframe" { + description = "Monitor timeframe for Virtual Machine requests failed [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_10m" +} + +variable "requests_failed_threshold_warning" { + description = "Virtual Machine requests failed limit (warning threshold)" + default = 90 +} + +variable "requests_failed_threshold_critical" { + description = "Virtual Machine requests failed limit (critical threshold)" + default = 95 +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/virtual-machine/modules.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/virtual-machine/modules.tf new file mode 100755 index 0000000..8be2bf9 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/virtual-machine/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "azure_virtual-machine" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/virtual-machine/monitors-virtual-machine.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/virtual-machine/monitors-virtual-machine.tf new file mode 100755 index 0000000..d952b4c --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/virtual-machine/monitors-virtual-machine.tf @@ -0,0 +1,183 @@ +resource "datadog_monitor" "virtualmachine_status" { + count = var.status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Virtual Machine is unreachable" + message = coalesce(var.status_message, var.message) + type = "query alert" + + query = < ${var.cpu_usage_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.cpu_usage_threshold_critical + warning = var.cpu_usage_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:virtualmachine", "team:claranet", "created-by:terraform"], var.cpu_usage_extra_tags) +} + +resource "datadog_monitor" "virtualmachine_credit_cpu_remaining_too_low" { + count = var.cpu_remaining_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Virtual Machine credit CPU {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cpu_remaining_rate_message, var.message) + type = "query alert" + + query = < ${var.ram_reserved_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.ram_reserved_threshold_critical + warning = var.ram_reserved_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:virtualmachine", "team:claranet", "created-by:terraform"], var.ram_reserved_extra_tags) +} + +resource "datadog_monitor" "virtualmachine_disk_space" { + count = var.disk_space_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Virtual Machine disk space {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.disk_space_message, var.message) + type = "query alert" + + query = < ${var.disk_space_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.disk_space_threshold_warning + critical = var.disk_space_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 1 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:virtualmachine", "team:claranet", "created-by:terraform"], var.disk_space_extra_tags) +} + +resource "datadog_monitor" "virtualmachine_requests_failed" { + count = var.requests_failed_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Virtual Machine requests failed {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.requests_failed_message, var.message) + type = "query alert" + + query = < ${var.requests_failed_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.requests_failed_threshold_critical + warning = var.requests_failed_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:azure", "resource:virtualmachine", "team:claranet", "created-by:terraform"], var.requests_failed_extra_tags) +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/virtual-machine/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/virtual-machine/outputs.tf new file mode 100755 index 0000000..fe9bffd --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/virtual-machine/outputs.tf @@ -0,0 +1,30 @@ +output "virtualmachine_cpu_usage_id" { + description = "id for monitor virtualmachine_cpu_usage" + value = datadog_monitor.virtualmachine_cpu_usage.*.id +} + +output "virtualmachine_credit_cpu_remaining_too_low_id" { + description = "id for monitor virtualmachine_credit_cpu_remaining_too_low" + value = datadog_monitor.virtualmachine_credit_cpu_remaining_too_low.*.id +} + +output "virtualmachine_disk_space_id" { + description = "id for monitor virtualmachine_disk_space" + value = datadog_monitor.virtualmachine_disk_space.*.id +} + +output "virtualmachine_ram_reserved_id" { + description = "id for monitor virtualmachine_ram_reserved" + value = datadog_monitor.virtualmachine_ram_reserved.*.id +} + +output "virtualmachine_requests_failed_id" { + description = "id for monitor virtualmachine_requests_failed" + value = datadog_monitor.virtualmachine_requests_failed.*.id +} + +output "virtualmachine_status_id" { + description = "id for monitor virtualmachine_status" + value = datadog_monitor.virtualmachine_status.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/azure/virtual-machine/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/virtual-machine/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/azure/virtual-machine/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/big-query/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/big-query/README.md new file mode 100755 index 0000000..8d378a5 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/big-query/README.md @@ -0,0 +1,144 @@ +# CLOUD GCP BIG-QUERY DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-gcp-big-query" { + source = "claranet/monitors/datadog//cloud/gcp/big-query" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- GCP Big Query Available Slots +- GCP Big Query Concurrent Queries +- GCP Big Query Execution Time +- GCP Big Query Scanned Bytes +- GCP Big Query Scanned Bytes Billed +- GCP Big Query Stored Bytes +- GCP Big Query Table Count +- GCP Big Query Uploaded Bytes +- GCP Big Query Uploaded Bytes Billed + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.available_slots](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.concurrent_queries](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.execution_time](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.scanned_bytes](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.scanned_bytes_billed](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.stored_bytes](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.table_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.uploaded_bytes](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.uploaded_bytes_billed](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [available\_slots\_enabled](#input\_available\_slots\_enabled) | Flag to enable GCP Big Query Available Slots monitor | `string` | `"true"` | no | +| [available\_slots\_extra\_tags](#input\_available\_slots\_extra\_tags) | Extra tags for GCP Big Query Available Slots monitor | `list(string)` | `[]` | no | +| [available\_slots\_message](#input\_available\_slots\_message) | Custom message for the Available Slots monitor | `string` | `""` | no | +| [available\_slots\_threshold\_critical](#input\_available\_slots\_threshold\_critical) | Available Slots (critical threshold) | `string` | `200` | no | +| [available\_slots\_threshold\_warning](#input\_available\_slots\_threshold\_warning) | Available Slots (warning threshold) | `string` | `300` | no | +| [available\_slots\_timeframe](#input\_available\_slots\_timeframe) | Timeframe for the Available Slots monitor | `string` | `"last_5m"` | no | +| [concurrent\_queries\_enabled](#input\_concurrent\_queries\_enabled) | Flag to enable GCP Big Query Concurrent Queries monitor | `string` | `"true"` | no | +| [concurrent\_queries\_extra\_tags](#input\_concurrent\_queries\_extra\_tags) | Extra tags for GCP Big Query Concurrent Queries monitor | `list(string)` | `[]` | no | +| [concurrent\_queries\_message](#input\_concurrent\_queries\_message) | Custom message for the Concurrent Queries monitor | `string` | `""` | no | +| [concurrent\_queries\_threshold\_critical](#input\_concurrent\_queries\_threshold\_critical) | Concurrent Queries (critical threshold) (hard limit 50) | `string` | `45` | no | +| [concurrent\_queries\_threshold\_warning](#input\_concurrent\_queries\_threshold\_warning) | Concurrent Queries (warning threshold) (hard limit 50) | `string` | `40` | no | +| [concurrent\_queries\_timeframe](#input\_concurrent\_queries\_timeframe) | Timeframe for the Concurrent Queries monitor | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [execution\_time\_enabled](#input\_execution\_time\_enabled) | Flag to enable GCP Big Query Execution Time monitor | `string` | `"true"` | no | +| [execution\_time\_extra\_tags](#input\_execution\_time\_extra\_tags) | Extra tags for GCP Big Query Execution Time monitor | `list(string)` | `[]` | no | +| [execution\_time\_message](#input\_execution\_time\_message) | Custom message for the Execution Time monitor | `string` | `""` | no | +| [execution\_time\_threshold\_critical](#input\_execution\_time\_threshold\_critical) | Average Execution Time in seconds (critical threshold) | `string` | `150` | no | +| [execution\_time\_threshold\_warning](#input\_execution\_time\_threshold\_warning) | Average Execution Time in seconds (warning threshold) | `string` | `100` | no | +| [execution\_time\_timeframe](#input\_execution\_time\_timeframe) | Timeframe for the Execution Time monitor | `string` | `"last_5m"` | no | +| [filter\_tags](#input\_filter\_tags) | Tags used for filtering | `string` | `"*"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the new host evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [scanned\_bytes\_billed\_enabled](#input\_scanned\_bytes\_billed\_enabled) | Flag to enable GCP Big Query Scanned Bytes Billed monitor | `string` | `"true"` | no | +| [scanned\_bytes\_billed\_extra\_tags](#input\_scanned\_bytes\_billed\_extra\_tags) | Extra tags for GCP Big Query Scanned Bytes Billed monitor | `list(string)` | `[]` | no | +| [scanned\_bytes\_billed\_message](#input\_scanned\_bytes\_billed\_message) | Custom message for the Scanned Bytes Billed monitor | `string` | `""` | no | +| [scanned\_bytes\_billed\_threshold\_critical](#input\_scanned\_bytes\_billed\_threshold\_critical) | Scanned Bytes Billed (critical threshold) | `string` | `1` | no | +| [scanned\_bytes\_billed\_threshold\_warning](#input\_scanned\_bytes\_billed\_threshold\_warning) | Scanned Bytes Billed (warning threshold) | `string` | `0` | no | +| [scanned\_bytes\_billed\_timeframe](#input\_scanned\_bytes\_billed\_timeframe) | Timeframe for the Scanned Bytes Billed monitor | `string` | `"last_4h"` | no | +| [scanned\_bytes\_enabled](#input\_scanned\_bytes\_enabled) | Flag to enable GCP Big Query Scanned Bytes monitor | `string` | `"true"` | no | +| [scanned\_bytes\_extra\_tags](#input\_scanned\_bytes\_extra\_tags) | Extra tags for GCP Big Query Scanned Bytes monitor | `list(string)` | `[]` | no | +| [scanned\_bytes\_message](#input\_scanned\_bytes\_message) | Custom message for the Scanned Bytes monitor | `string` | `""` | no | +| [scanned\_bytes\_threshold\_critical](#input\_scanned\_bytes\_threshold\_critical) | Scanned Bytes (critical threshold) | `string` | `1` | no | +| [scanned\_bytes\_threshold\_warning](#input\_scanned\_bytes\_threshold\_warning) | Scanned Bytes (warning threshold) | `string` | `0` | no | +| [scanned\_bytes\_timeframe](#input\_scanned\_bytes\_timeframe) | Timeframe for the Scanned Bytes monitor | `string` | `"last_4h"` | no | +| [stored\_bytes\_enabled](#input\_stored\_bytes\_enabled) | Flag to enable GCP Big Query Stored Bytes monitor | `string` | `"true"` | no | +| [stored\_bytes\_extra\_tags](#input\_stored\_bytes\_extra\_tags) | Extra tags for GCP Big Query Stored Bytes monitor | `list(string)` | `[]` | no | +| [stored\_bytes\_message](#input\_stored\_bytes\_message) | Custom message for the Stored Bytes monitor | `string` | `""` | no | +| [stored\_bytes\_threshold\_critical](#input\_stored\_bytes\_threshold\_critical) | Stored Bytes in fraction (critical threshold) | `string` | `1` | no | +| [stored\_bytes\_threshold\_warning](#input\_stored\_bytes\_threshold\_warning) | Stored Bytes in fraction (warning threshold) | `string` | `0` | no | +| [stored\_bytes\_timeframe](#input\_stored\_bytes\_timeframe) | Timeframe for the Stored Bytes monitor | `string` | `"last_5m"` | no | +| [table\_count\_enabled](#input\_table\_count\_enabled) | Flag to enable GCP Big Query Table Count monitor | `string` | `"true"` | no | +| [table\_count\_extra\_tags](#input\_table\_count\_extra\_tags) | Extra tags for GCP Big Query Table Count monitor | `list(string)` | `[]` | no | +| [table\_count\_message](#input\_table\_count\_message) | Custom message for the Table Count monitor | `string` | `""` | no | +| [table\_count\_threshold\_critical](#input\_table\_count\_threshold\_critical) | Table Count (critical threshold) | `string` | `1` | no | +| [table\_count\_threshold\_warning](#input\_table\_count\_threshold\_warning) | Table Count (warning threshold) | `string` | `0` | no | +| [table\_count\_timeframe](#input\_table\_count\_timeframe) | Timeframe for the Table Count monitor | `string` | `"last_4h"` | no | +| [uploaded\_bytes\_billed\_enabled](#input\_uploaded\_bytes\_billed\_enabled) | Flag to enable GCP Big Query Uploaded Bytes Billed monitor | `string` | `"true"` | no | +| [uploaded\_bytes\_billed\_extra\_tags](#input\_uploaded\_bytes\_billed\_extra\_tags) | Extra tags for GCP Big Query Scanned Bytes monitor | `list(string)` | `[]` | no | +| [uploaded\_bytes\_billed\_message](#input\_uploaded\_bytes\_billed\_message) | Custom message for the Uploaded Bytes Billed monitor | `string` | `""` | no | +| [uploaded\_bytes\_billed\_threshold\_critical](#input\_uploaded\_bytes\_billed\_threshold\_critical) | Uploaded Bytes Billed (critical threshold) | `string` | `1` | no | +| [uploaded\_bytes\_billed\_threshold\_warning](#input\_uploaded\_bytes\_billed\_threshold\_warning) | Uploaded Bytes Billed (warning threshold) | `string` | `0` | no | +| [uploaded\_bytes\_billed\_timeframe](#input\_uploaded\_bytes\_billed\_timeframe) | Timeframe for the Uploaded Bytes Billed monitor | `string` | `"last_4h"` | no | +| [uploaded\_bytes\_enabled](#input\_uploaded\_bytes\_enabled) | Flag to enable GCP Big Query Uploaded Bytes monitor | `string` | `"true"` | no | +| [uploaded\_bytes\_extra\_tags](#input\_uploaded\_bytes\_extra\_tags) | Extra tags for GCP Big Query Uploaded Bytes monitor | `list(string)` | `[]` | no | +| [uploaded\_bytes\_message](#input\_uploaded\_bytes\_message) | Custom message for the Uploaded Bytes monitor | `string` | `""` | no | +| [uploaded\_bytes\_threshold\_critical](#input\_uploaded\_bytes\_threshold\_critical) | Uploaded Bytes (critical threshold) | `string` | `1` | no | +| [uploaded\_bytes\_threshold\_warning](#input\_uploaded\_bytes\_threshold\_warning) | Uploaded Bytes (warning threshold) | `string` | `0` | no | +| [uploaded\_bytes\_timeframe](#input\_uploaded\_bytes\_timeframe) | Timeframe for the Uploaded Bytes monitor | `string` | `"last_4h"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [available\_slots\_id](#output\_available\_slots\_id) | id for monitor available\_slots | +| [concurrent\_queries\_id](#output\_concurrent\_queries\_id) | id for monitor concurrent\_queries | +| [execution\_time\_id](#output\_execution\_time\_id) | id for monitor execution\_time | +| [scanned\_bytes\_billed\_id](#output\_scanned\_bytes\_billed\_id) | id for monitor scanned\_bytes\_billed | +| [scanned\_bytes\_id](#output\_scanned\_bytes\_id) | id for monitor scanned\_bytes | +| [stored\_bytes\_id](#output\_stored\_bytes\_id) | id for monitor stored\_bytes | +| [table\_count\_id](#output\_table\_count\_id) | id for monitor table\_count | +| [uploaded\_bytes\_billed\_id](#output\_uploaded\_bytes\_billed\_id) | id for monitor uploaded\_bytes\_billed | +| [uploaded\_bytes\_id](#output\_uploaded\_bytes\_id) | id for monitor uploaded\_bytes | +## Related documentation + +* [GCP Big Query monitoring](https://cloud.google.com/bigquery/docs/monitoring) +* [Datadog Integration for GCP Big Query](https://docs.datadoghq.com/integrations/google_cloud_big_query/) +* [GCP Big Query Quotas and Limits](https://cloud.google.com/bigquery/quotas) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/big-query/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/big-query/inputs.tf new file mode 100755 index 0000000..71edb3c --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/big-query/inputs.tf @@ -0,0 +1,398 @@ +# +# Datadog global variables +# + +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags" { + description = "Tags used for filtering" + default = "*" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds for the new host evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# +# Concurrent queries +# + +variable "concurrent_queries_message" { + description = "Custom message for the Concurrent Queries monitor" + type = string + default = "" +} + +variable "concurrent_queries_timeframe" { + description = "Timeframe for the Concurrent Queries monitor" + type = string + default = "last_5m" +} + +variable "concurrent_queries_threshold_warning" { + description = "Concurrent Queries (warning threshold) (hard limit 50)" + type = string + default = 40 +} + +variable "concurrent_queries_threshold_critical" { + description = "Concurrent Queries (critical threshold) (hard limit 50)" + type = string + default = 45 +} + +variable "concurrent_queries_enabled" { + description = "Flag to enable GCP Big Query Concurrent Queries monitor" + type = string + default = "true" +} + +variable "concurrent_queries_extra_tags" { + description = "Extra tags for GCP Big Query Concurrent Queries monitor" + type = list(string) + default = [] +} + +# +# Execution Time +# + +variable "execution_time_message" { + description = "Custom message for the Execution Time monitor" + type = string + default = "" +} + +variable "execution_time_timeframe" { + description = "Timeframe for the Execution Time monitor" + type = string + default = "last_5m" +} + +variable "execution_time_threshold_warning" { + description = "Average Execution Time in seconds (warning threshold)" + type = string + default = 100 +} + +variable "execution_time_threshold_critical" { + description = "Average Execution Time in seconds (critical threshold)" + type = string + default = 150 +} + +variable "execution_time_enabled" { + description = "Flag to enable GCP Big Query Execution Time monitor" + type = string + default = "true" +} + +variable "execution_time_extra_tags" { + description = "Extra tags for GCP Big Query Execution Time monitor" + type = list(string) + default = [] +} + +# +# Scanned Bytes +# + +variable "scanned_bytes_message" { + description = "Custom message for the Scanned Bytes monitor" + type = string + default = "" +} + +variable "scanned_bytes_timeframe" { + description = "Timeframe for the Scanned Bytes monitor" + type = string + default = "last_4h" +} + +variable "scanned_bytes_threshold_warning" { + description = "Scanned Bytes (warning threshold)" + type = string + default = 0 +} + +variable "scanned_bytes_threshold_critical" { + description = "Scanned Bytes (critical threshold)" + type = string + default = 1 +} + +variable "scanned_bytes_enabled" { + description = "Flag to enable GCP Big Query Scanned Bytes monitor" + type = string + default = "true" +} + +variable "scanned_bytes_extra_tags" { + description = "Extra tags for GCP Big Query Scanned Bytes monitor" + type = list(string) + default = [] +} + +# +# Scanned Bytes Billed +# + +variable "scanned_bytes_billed_message" { + description = "Custom message for the Scanned Bytes Billed monitor" + type = string + default = "" +} + +variable "scanned_bytes_billed_timeframe" { + description = "Timeframe for the Scanned Bytes Billed monitor" + type = string + default = "last_4h" +} + +variable "scanned_bytes_billed_threshold_warning" { + description = "Scanned Bytes Billed (warning threshold)" + type = string + default = 0 +} + +variable "scanned_bytes_billed_threshold_critical" { + description = "Scanned Bytes Billed (critical threshold)" + type = string + default = 1 +} + +variable "scanned_bytes_billed_enabled" { + description = "Flag to enable GCP Big Query Scanned Bytes Billed monitor" + type = string + default = "true" +} + +variable "scanned_bytes_billed_extra_tags" { + description = "Extra tags for GCP Big Query Scanned Bytes Billed monitor" + type = list(string) + default = [] +} + +# +# Available Slots +# + +variable "available_slots_message" { + description = "Custom message for the Available Slots monitor" + type = string + default = "" +} + +variable "available_slots_timeframe" { + description = "Timeframe for the Available Slots monitor" + type = string + default = "last_5m" +} + +variable "available_slots_threshold_warning" { + description = "Available Slots (warning threshold)" + type = string + default = 300 +} + +variable "available_slots_threshold_critical" { + description = "Available Slots (critical threshold)" + type = string + default = 200 +} + +variable "available_slots_enabled" { + description = "Flag to enable GCP Big Query Available Slots monitor" + type = string + default = "true" +} + +variable "available_slots_extra_tags" { + description = "Extra tags for GCP Big Query Available Slots monitor" + type = list(string) + default = [] +} + +# +# Stored Bytes +# + +variable "stored_bytes_message" { + description = "Custom message for the Stored Bytes monitor" + type = string + default = "" +} + +variable "stored_bytes_timeframe" { + description = "Timeframe for the Stored Bytes monitor" + type = string + default = "last_5m" +} + +variable "stored_bytes_threshold_warning" { + description = "Stored Bytes in fraction (warning threshold)" + type = string + default = 0 +} + +variable "stored_bytes_threshold_critical" { + description = "Stored Bytes in fraction (critical threshold)" + type = string + default = 1 +} + +variable "stored_bytes_enabled" { + description = "Flag to enable GCP Big Query Stored Bytes monitor" + type = string + default = "true" +} + +variable "stored_bytes_extra_tags" { + description = "Extra tags for GCP Big Query Stored Bytes monitor" + type = list(string) + default = [] +} + +# +# Table Count +# + +variable "table_count_message" { + description = "Custom message for the Table Count monitor" + type = string + default = "" +} + +variable "table_count_timeframe" { + description = "Timeframe for the Table Count monitor" + type = string + default = "last_4h" +} + +variable "table_count_threshold_warning" { + description = "Table Count (warning threshold)" + type = string + default = 0 +} + +variable "table_count_threshold_critical" { + description = "Table Count (critical threshold)" + type = string + default = 1 +} + +variable "table_count_enabled" { + description = "Flag to enable GCP Big Query Table Count monitor" + type = string + default = "true" +} + +variable "table_count_extra_tags" { + description = "Extra tags for GCP Big Query Table Count monitor" + type = list(string) + default = [] +} + +# +# Uploaded Bytes +# + +variable "uploaded_bytes_message" { + description = "Custom message for the Uploaded Bytes monitor" + type = string + default = "" +} + +variable "uploaded_bytes_timeframe" { + description = "Timeframe for the Uploaded Bytes monitor" + type = string + default = "last_4h" +} + +variable "uploaded_bytes_threshold_warning" { + description = "Uploaded Bytes (warning threshold)" + type = string + default = 0 +} + +variable "uploaded_bytes_threshold_critical" { + description = "Uploaded Bytes (critical threshold)" + type = string + default = 1 +} + +variable "uploaded_bytes_enabled" { + description = "Flag to enable GCP Big Query Uploaded Bytes monitor" + type = string + default = "true" +} + +variable "uploaded_bytes_extra_tags" { + description = "Extra tags for GCP Big Query Uploaded Bytes monitor" + type = list(string) + default = [] +} + +# +# Uploaded Bytes Billed +# + +variable "uploaded_bytes_billed_message" { + description = "Custom message for the Uploaded Bytes Billed monitor" + type = string + default = "" +} + +variable "uploaded_bytes_billed_timeframe" { + description = "Timeframe for the Uploaded Bytes Billed monitor" + type = string + default = "last_4h" +} + +variable "uploaded_bytes_billed_threshold_warning" { + description = "Uploaded Bytes Billed (warning threshold)" + type = string + default = 0 +} + +variable "uploaded_bytes_billed_threshold_critical" { + description = "Uploaded Bytes Billed (critical threshold)" + type = string + default = 1 +} + +variable "uploaded_bytes_billed_enabled" { + description = "Flag to enable GCP Big Query Uploaded Bytes Billed monitor" + type = string + default = "true" +} + +variable "uploaded_bytes_billed_extra_tags" { + description = "Extra tags for GCP Big Query Scanned Bytes monitor" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/big-query/monitors-big-query.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/big-query/monitors-big-query.tf new file mode 100755 index 0000000..82ee6c4 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/big-query/monitors-big-query.tf @@ -0,0 +1,297 @@ +# +# Concurrent queries +# +resource "datadog_monitor" "concurrent_queries" { + count = var.concurrent_queries_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP Big Query Concurrent Queries {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.concurrent_queries_message, var.message) + type = "query alert" + + query = < ${var.concurrent_queries_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.concurrent_queries_threshold_warning + critical = var.concurrent_queries_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + include_tags = true + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:big-query", "team:claranet", "created-by:terraform"], var.concurrent_queries_extra_tags) +} + +# +# Execution Time +# +resource "datadog_monitor" "execution_time" { + count = var.execution_time_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP Big Query Execution Time {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + message = coalesce(var.execution_time_message, var.message) + type = "query alert" + + query = < ${var.execution_time_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.execution_time_threshold_warning + critical = var.execution_time_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + include_tags = true + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:big-query", "team:claranet", "created-by:terraform"], var.execution_time_extra_tags) +} + +# +# Scanned Bytes +# +resource "datadog_monitor" "scanned_bytes" { + count = var.scanned_bytes_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP Big Query Scanned Bytes {{#is_alert}}{{{comparator}}} {{threshold}}B/mn ({{value}}B/mn){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}B/mn ({{value}}B/mn){{/is_warning}}" + message = coalesce(var.scanned_bytes_message, var.message) + type = "query alert" + + query = < ${var.scanned_bytes_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.scanned_bytes_threshold_warning + critical = var.scanned_bytes_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + include_tags = true + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:big-query", "team:claranet", "created-by:terraform"], var.scanned_bytes_extra_tags) +} + +# +# Scanned Bytes Billed +# +resource "datadog_monitor" "scanned_bytes_billed" { + count = var.scanned_bytes_billed_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP Big Query Scanned Bytes Billed {{#is_alert}}{{{comparator}}} {{threshold}}B/mn ({{value}}B/mn){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}B/mn ({{value}}B/mn){{/is_warning}}" + message = coalesce(var.scanned_bytes_billed_message, var.message) + type = "query alert" + + query = < ${var.scanned_bytes_billed_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.scanned_bytes_billed_threshold_warning + critical = var.scanned_bytes_billed_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + include_tags = true + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:big-query", "team:claranet", "created-by:terraform"], var.scanned_bytes_billed_extra_tags) +} + +# +# Available Slots +# +resource "datadog_monitor" "available_slots" { + count = var.available_slots_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP Big Query Available Slots {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.available_slots_message, var.message) + type = "metric alert" + + query = < ${var.stored_bytes_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.stored_bytes_threshold_warning + critical = var.stored_bytes_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + include_tags = true + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:big-query", "team:claranet", "created-by:terraform"], var.stored_bytes_extra_tags) +} + +# +# Table Count +# +resource "datadog_monitor" "table_count" { + count = var.table_count_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP Big Query Table Count {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.table_count_message, var.message) + type = "metric alert" + + query = < ${var.table_count_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.table_count_threshold_warning + critical = var.table_count_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + include_tags = true + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:big-query", "team:claranet", "created-by:terraform"], var.table_count_extra_tags) +} + +# +# Uploaded Bytes +# +resource "datadog_monitor" "uploaded_bytes" { + count = var.uploaded_bytes_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP Big Query Uploaded Bytes {{#is_alert}}{{{comparator}}} {{threshold}}B/mn ({{value}}B/mn){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}B/mn ({{value}}B/mn){{/is_warning}}" + message = coalesce(var.uploaded_bytes_message, var.message) + type = "query alert" + + query = < ${var.uploaded_bytes_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.uploaded_bytes_threshold_warning + critical = var.uploaded_bytes_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + include_tags = true + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:big-query", "team:claranet", "created-by:terraform"], var.uploaded_bytes_extra_tags) +} + +# +# Uploaded Bytes Billed +# +resource "datadog_monitor" "uploaded_bytes_billed" { + count = var.uploaded_bytes_billed_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP Big Query Uploaded Bytes Billed {{#is_alert}}{{{comparator}}} {{threshold}}B/mn ({{value}}B/mn){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}B/mn ({{value}}B/mn){{/is_warning}}" + message = coalesce(var.uploaded_bytes_billed_message, var.message) + type = "query alert" + + query = < ${var.uploaded_bytes_billed_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.uploaded_bytes_billed_threshold_warning + critical = var.uploaded_bytes_billed_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + include_tags = true + notify_no_data = false + require_full_window = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + locked = false + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:big-query", "team:claranet", "created-by:terraform"], var.uploaded_bytes_billed_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/big-query/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/big-query/outputs.tf new file mode 100755 index 0000000..f3153bf --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/big-query/outputs.tf @@ -0,0 +1,45 @@ +output "available_slots_id" { + description = "id for monitor available_slots" + value = datadog_monitor.available_slots.*.id +} + +output "concurrent_queries_id" { + description = "id for monitor concurrent_queries" + value = datadog_monitor.concurrent_queries.*.id +} + +output "execution_time_id" { + description = "id for monitor execution_time" + value = datadog_monitor.execution_time.*.id +} + +output "scanned_bytes_id" { + description = "id for monitor scanned_bytes" + value = datadog_monitor.scanned_bytes.*.id +} + +output "scanned_bytes_billed_id" { + description = "id for monitor scanned_bytes_billed" + value = datadog_monitor.scanned_bytes_billed.*.id +} + +output "stored_bytes_id" { + description = "id for monitor stored_bytes" + value = datadog_monitor.stored_bytes.*.id +} + +output "table_count_id" { + description = "id for monitor table_count" + value = datadog_monitor.table_count.*.id +} + +output "uploaded_bytes_id" { + description = "id for monitor uploaded_bytes" + value = datadog_monitor.uploaded_bytes.*.id +} + +output "uploaded_bytes_billed_id" { + description = "id for monitor uploaded_bytes_billed" + value = datadog_monitor.uploaded_bytes_billed.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/big-query/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/big-query/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/big-query/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/common/MANIFEST.txt b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/common/MANIFEST.txt new file mode 100755 index 0000000..6de6b50 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/common/MANIFEST.txt @@ -0,0 +1 @@ +cloud-gcp diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/common/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/common/README.md new file mode 100755 index 0000000..20830dc --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/common/README.md @@ -0,0 +1,135 @@ +# CLOUD GCP CLOUD-SQL COMMON DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-gcp-cloud-sql-common" { + source = "claranet/monitors/datadog//cloud/gcp/cloud-sql/common" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Cloud SQL CPU Utilization +- Cloud SQL Disk Utilization +- Cloud SQL Disk Utilization forecast +- Cloud SQL Failover Unavailable +- Cloud SQL Memory Utilization +- Cloud SQL Memory Utilization forecast (disabled by default) + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cpu_utilization](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.disk_utilization](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.disk_utilization_forecast](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.failover_unavailable](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.memory_utilization](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.memory_utilization_forecast](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_utilization\_enabled](#input\_cpu\_utilization\_enabled) | Flag to enable GCP Cloud SQL CPU Utilization monitor | `string` | `"true"` | no | +| [cpu\_utilization\_extra\_tags](#input\_cpu\_utilization\_extra\_tags) | Extra tags for GCP Cloud SQL CPU Utilization monitor | `list(string)` | `[]` | no | +| [cpu\_utilization\_message](#input\_cpu\_utilization\_message) | Custom message for the CPU Utilization monitor | `string` | `""` | no | +| [cpu\_utilization\_threshold\_critical](#input\_cpu\_utilization\_threshold\_critical) | CPU Utilization in percentage (critical threshold) | `string` | `90` | no | +| [cpu\_utilization\_threshold\_warning](#input\_cpu\_utilization\_threshold\_warning) | CPU Utilization in percentage (warning threshold) | `string` | `80` | no | +| [cpu\_utilization\_time\_aggregator](#input\_cpu\_utilization\_time\_aggregator) | Time aggregator for the CPU Utilization monitor | `string` | `"avg"` | no | +| [cpu\_utilization\_timeframe](#input\_cpu\_utilization\_timeframe) | Timeframe for the CPU Utilization monitor | `string` | `"last_15m"` | no | +| [disk\_utilization\_enabled](#input\_disk\_utilization\_enabled) | Flag to enable GCP Cloud SQL Disk Utilization monitor | `string` | `"true"` | no | +| [disk\_utilization\_extra\_tags](#input\_disk\_utilization\_extra\_tags) | Extra tags for GCP Cloud SQL CPU Utilization monitor | `list(string)` | `[]` | no | +| [disk\_utilization\_forecast\_algorithm](#input\_disk\_utilization\_forecast\_algorithm) | Algorithm for the Disk Utilization Forecast monitor | `string` | `"linear"` | no | +| [disk\_utilization\_forecast\_deviations](#input\_disk\_utilization\_forecast\_deviations) | Deviations for the Disk Utilization Forecast monitor | `string` | `1` | no | +| [disk\_utilization\_forecast\_enabled](#input\_disk\_utilization\_forecast\_enabled) | Flag to enable GCP Cloud SQL Disk Utilization Forecast monitor | `string` | `"true"` | no | +| [disk\_utilization\_forecast\_extra\_tags](#input\_disk\_utilization\_forecast\_extra\_tags) | Extra tags for GCP Cloud SQL Disk Utilization Forecast monitor | `list(string)` | `[]` | no | +| [disk\_utilization\_forecast\_interval](#input\_disk\_utilization\_forecast\_interval) | Interval for the Disk Utilization Forecast monitor | `string` | `"60m"` | no | +| [disk\_utilization\_forecast\_linear\_history](#input\_disk\_utilization\_forecast\_linear\_history) | History for the Disk Utilization Forecast monitor | `string` | `"3d"` | no | +| [disk\_utilization\_forecast\_linear\_model](#input\_disk\_utilization\_forecast\_linear\_model) | Model for the Disk Utilization Forecast monitor | `string` | `"default"` | no | +| [disk\_utilization\_forecast\_message](#input\_disk\_utilization\_forecast\_message) | Custom message for the Disk Utilization Forecast monitor | `string` | `""` | no | +| [disk\_utilization\_forecast\_seasonal\_seasonality](#input\_disk\_utilization\_forecast\_seasonal\_seasonality) | Seasonality for the Disk Utilization Forecast monitor | `string` | `"weekly"` | no | +| [disk\_utilization\_forecast\_threshold\_critical](#input\_disk\_utilization\_forecast\_threshold\_critical) | Disk Utilization Forecast in percentage (critical threshold) | `string` | `80` | no | +| [disk\_utilization\_forecast\_threshold\_critical\_recovery](#input\_disk\_utilization\_forecast\_threshold\_critical\_recovery) | Disk Utilization Forecast in percentage (recovery threshold) | `string` | `72` | no | +| [disk\_utilization\_forecast\_time\_aggregator](#input\_disk\_utilization\_forecast\_time\_aggregator) | Time aggregator for the Disk Utilization Forecast monitor | `string` | `"max"` | no | +| [disk\_utilization\_forecast\_timeframe](#input\_disk\_utilization\_forecast\_timeframe) | Timeframe for the Disk Utilization Forecast monitor | `string` | `"next_1w"` | no | +| [disk\_utilization\_message](#input\_disk\_utilization\_message) | Custom message for the Disk Utilization monitor | `string` | `""` | no | +| [disk\_utilization\_no\_data\_timeframe](#input\_disk\_utilization\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [disk\_utilization\_threshold\_critical](#input\_disk\_utilization\_threshold\_critical) | Disk Utilization in percentage (critical threshold) | `string` | `90` | no | +| [disk\_utilization\_threshold\_warning](#input\_disk\_utilization\_threshold\_warning) | Disk Utilization in percentage (warning threshold) | `string` | `80` | no | +| [disk\_utilization\_time\_aggregator](#input\_disk\_utilization\_time\_aggregator) | Time aggregator for the Disk Utilization monitor | `string` | `"avg"` | no | +| [disk\_utilization\_timeframe](#input\_disk\_utilization\_timeframe) | Timeframe for the Disk Utilization monitor | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [failover\_unavailable\_enabled](#input\_failover\_unavailable\_enabled) | Flag to enable GCP Cloud SQL Failover Unavailable monitor | `string` | `"true"` | no | +| [failover\_unavailable\_extra\_tags](#input\_failover\_unavailable\_extra\_tags) | Extra tags for GCP Cloud SQL Failover Unavailable monitor | `list(string)` | `[]` | no | +| [failover\_unavailable\_message](#input\_failover\_unavailable\_message) | Custom message for the Failover Unavailable monitor | `string` | `""` | no | +| [failover\_unavailable\_threshold\_critical](#input\_failover\_unavailable\_threshold\_critical) | Failover Unavailable critical threshold | `string` | `0` | no | +| [failover\_unavailable\_time\_aggregator](#input\_failover\_unavailable\_time\_aggregator) | Time aggreggator for the Failover Unavailable monitor | `string` | `"max"` | no | +| [failover\_unavailable\_timeframe](#input\_failover\_unavailable\_timeframe) | Timeframe for the Failover Unavailable monitor | `string` | `"last_10m"` | no | +| [filter\_tags](#input\_filter\_tags) | Tags used for filtering | `string` | `"*"` | no | +| [filter\_tags\_failover\_unavailable](#input\_filter\_tags\_failover\_unavailable) | Tags used for filtering specific to the failover unavailable monitor which is only useful for master instances | `string` | `""` | no | +| [memory\_utilization\_enabled](#input\_memory\_utilization\_enabled) | Flag to enable GCP Cloud SQL Memory Utilization monitor | `string` | `"true"` | no | +| [memory\_utilization\_extra\_tags](#input\_memory\_utilization\_extra\_tags) | Extra tags for GCP Cloud SQL Memory Utilization monitor | `list(string)` | `[]` | no | +| [memory\_utilization\_forecast\_algorithm](#input\_memory\_utilization\_forecast\_algorithm) | Algorithm for the Memory Utilization Forecast monitor | `string` | `"linear"` | no | +| [memory\_utilization\_forecast\_deviations](#input\_memory\_utilization\_forecast\_deviations) | Deviations for the Memory Utilization Forecast monitor | `string` | `1` | no | +| [memory\_utilization\_forecast\_enabled](#input\_memory\_utilization\_forecast\_enabled) | Flag to enable GCP Cloud SQL Memory Utilization Forecast monitor | `string` | `"false"` | no | +| [memory\_utilization\_forecast\_extra\_tags](#input\_memory\_utilization\_forecast\_extra\_tags) | Extra tags for GCP Cloud SQL Memory Utilization Forecast monitor | `list(string)` | `[]` | no | +| [memory\_utilization\_forecast\_interval](#input\_memory\_utilization\_forecast\_interval) | Interval for the Memory Utilization Forecast monitor | `string` | `"30m"` | no | +| [memory\_utilization\_forecast\_linear\_history](#input\_memory\_utilization\_forecast\_linear\_history) | History for the Memory Utilization Forecast monitor | `string` | `"12h"` | no | +| [memory\_utilization\_forecast\_linear\_model](#input\_memory\_utilization\_forecast\_linear\_model) | Model for the Memory Utilization Forecast monitor | `string` | `"default"` | no | +| [memory\_utilization\_forecast\_message](#input\_memory\_utilization\_forecast\_message) | Custom message for the Memory Utilization Forecast monitor | `string` | `""` | no | +| [memory\_utilization\_forecast\_seasonal\_seasonality](#input\_memory\_utilization\_forecast\_seasonal\_seasonality) | Seasonality for the Memory Utilization Forecast monitor | `string` | `"weekly"` | no | +| [memory\_utilization\_forecast\_threshold\_critical](#input\_memory\_utilization\_forecast\_threshold\_critical) | Memory Utilization Forecast in percentage (warning threshold) | `number` | `90` | no | +| [memory\_utilization\_forecast\_threshold\_critical\_recovery](#input\_memory\_utilization\_forecast\_threshold\_critical\_recovery) | Memory Utilization Forecast in percentage (recovery threshold) | `number` | `81` | no | +| [memory\_utilization\_forecast\_time\_aggregator](#input\_memory\_utilization\_forecast\_time\_aggregator) | Time aggregator for the Memory Utilization Forecast monitor | `string` | `"max"` | no | +| [memory\_utilization\_forecast\_timeframe](#input\_memory\_utilization\_forecast\_timeframe) | Timeframe for the Memory Utilization Forecast monitor | `string` | `"next_3d"` | no | +| [memory\_utilization\_message](#input\_memory\_utilization\_message) | Custom message for the Memory Utilization monitor | `string` | `""` | no | +| [memory\_utilization\_threshold\_critical](#input\_memory\_utilization\_threshold\_critical) | Memory Utilization in percentage (critical threshold) | `number` | `90` | no | +| [memory\_utilization\_threshold\_warning](#input\_memory\_utilization\_threshold\_warning) | Memory Utilization in percentage (warning threshold) | `number` | `80` | no | +| [memory\_utilization\_time\_aggregator](#input\_memory\_utilization\_time\_aggregator) | Time aggregator for the Memory Utilization monitor | `string` | `"avg"` | no | +| [memory\_utilization\_timeframe](#input\_memory\_utilization\_timeframe) | Timeframe for the Memory Utilization monitor | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the new host evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cpu\_utilization\_id](#output\_cpu\_utilization\_id) | id for monitor cpu\_utilization | +| [disk\_utilization\_forecast\_id](#output\_disk\_utilization\_forecast\_id) | id for monitor disk\_utilization\_forecast | +| [disk\_utilization\_id](#output\_disk\_utilization\_id) | id for monitor disk\_utilization | +| [failover\_unavailable\_id](#output\_failover\_unavailable\_id) | id for monitor failover\_unavailable | +| [memory\_utilization\_forecast\_id](#output\_memory\_utilization\_forecast\_id) | id for monitor memory\_utilization\_forecast | +| [memory\_utilization\_id](#output\_memory\_utilization\_id) | id for monitor memory\_utilization | +## Related documentation + +* [GCP Metrics for CloudSQL](https://cloud.google.com/monitoring/api/metrics_gcp#gcp-cloudsql) +* [Datadog Useful monitors for GCP CloudSQL](https://www.datadoghq.com/blog/monitor-google-cloud-sql/) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/common/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/common/inputs.tf new file mode 100755 index 0000000..6063dce --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/common/inputs.tf @@ -0,0 +1,380 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags" { + description = "Tags used for filtering" + default = "*" +} + +variable "filter_tags_failover_unavailable" { + description = "Tags used for filtering specific to the failover unavailable monitor which is only useful for master instances" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds for the new host evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "disk_utilization_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +# +# CPU +# + +variable "cpu_utilization_message" { + description = "Custom message for the CPU Utilization monitor" + type = string + default = "" +} + +variable "cpu_utilization_time_aggregator" { + description = "Time aggregator for the CPU Utilization monitor" + type = string + default = "avg" +} + +variable "cpu_utilization_timeframe" { + description = "Timeframe for the CPU Utilization monitor" + type = string + default = "last_15m" +} + +variable "cpu_utilization_threshold_warning" { + description = "CPU Utilization in percentage (warning threshold)" + type = string + default = 80 +} + +variable "cpu_utilization_threshold_critical" { + description = "CPU Utilization in percentage (critical threshold)" + type = string + default = 90 +} + +variable "cpu_utilization_enabled" { + description = "Flag to enable GCP Cloud SQL CPU Utilization monitor" + type = string + default = "true" +} + +variable "cpu_utilization_extra_tags" { + description = "Extra tags for GCP Cloud SQL CPU Utilization monitor" + type = list(string) + default = [] +} + +# +# DISK Utilization +# + +variable "disk_utilization_message" { + description = "Custom message for the Disk Utilization monitor" + type = string + default = "" +} + +variable "disk_utilization_time_aggregator" { + description = "Time aggregator for the Disk Utilization monitor" + type = string + default = "avg" +} + +variable "disk_utilization_timeframe" { + description = "Timeframe for the Disk Utilization monitor" + type = string + default = "last_5m" +} + +variable "disk_utilization_threshold_warning" { + description = "Disk Utilization in percentage (warning threshold)" + type = string + default = 80 +} + +variable "disk_utilization_threshold_critical" { + description = "Disk Utilization in percentage (critical threshold)" + type = string + default = 90 +} + +variable "disk_utilization_enabled" { + description = "Flag to enable GCP Cloud SQL Disk Utilization monitor" + type = string + default = "true" +} + +variable "disk_utilization_extra_tags" { + description = "Extra tags for GCP Cloud SQL CPU Utilization monitor" + type = list(string) + default = [] +} + +# +# DISK Utilization Forecast +# + +variable "disk_utilization_forecast_message" { + description = "Custom message for the Disk Utilization Forecast monitor" + type = string + default = "" +} + +variable "disk_utilization_forecast_time_aggregator" { + description = "Time aggregator for the Disk Utilization Forecast monitor" + type = string + default = "max" +} + +variable "disk_utilization_forecast_timeframe" { + description = "Timeframe for the Disk Utilization Forecast monitor" + type = string + default = "next_1w" +} + +variable "disk_utilization_forecast_algorithm" { + description = "Algorithm for the Disk Utilization Forecast monitor" + type = string + default = "linear" +} + +variable "disk_utilization_forecast_deviations" { + description = "Deviations for the Disk Utilization Forecast monitor" + type = string + default = 1 +} + +variable "disk_utilization_forecast_interval" { + description = "Interval for the Disk Utilization Forecast monitor" + type = string + default = "60m" +} + +variable "disk_utilization_forecast_linear_history" { + description = "History for the Disk Utilization Forecast monitor" + type = string + default = "3d" +} + +variable "disk_utilization_forecast_linear_model" { + description = "Model for the Disk Utilization Forecast monitor" + type = string + default = "default" +} + +variable "disk_utilization_forecast_seasonal_seasonality" { + description = "Seasonality for the Disk Utilization Forecast monitor" + type = string + default = "weekly" +} + +variable "disk_utilization_forecast_threshold_critical" { + description = "Disk Utilization Forecast in percentage (critical threshold)" + type = string + default = 80 +} + +variable "disk_utilization_forecast_threshold_critical_recovery" { + description = "Disk Utilization Forecast in percentage (recovery threshold)" + type = string + default = 72 +} + +variable "disk_utilization_forecast_enabled" { + description = "Flag to enable GCP Cloud SQL Disk Utilization Forecast monitor" + type = string + default = "true" +} + +variable "disk_utilization_forecast_extra_tags" { + description = "Extra tags for GCP Cloud SQL Disk Utilization Forecast monitor" + type = list(string) + default = [] +} + +# +# Memory Utilization +# + +variable "memory_utilization_message" { + description = "Custom message for the Memory Utilization monitor" + default = "" +} + +variable "memory_utilization_time_aggregator" { + description = "Time aggregator for the Memory Utilization monitor" + default = "avg" +} + +variable "memory_utilization_timeframe" { + description = "Timeframe for the Memory Utilization monitor" + default = "last_5m" +} + +variable "memory_utilization_threshold_warning" { + description = "Memory Utilization in percentage (warning threshold)" + default = 80 +} + +variable "memory_utilization_threshold_critical" { + description = "Memory Utilization in percentage (critical threshold)" + default = 90 +} + +variable "memory_utilization_enabled" { + description = "Flag to enable GCP Cloud SQL Memory Utilization monitor" + type = string + default = "true" +} + +variable "memory_utilization_extra_tags" { + description = "Extra tags for GCP Cloud SQL Memory Utilization monitor" + type = list(string) + default = [] +} + +# +# Memory Utilization Forecast +# + +variable "memory_utilization_forecast_message" { + description = "Custom message for the Memory Utilization Forecast monitor" + default = "" +} + +variable "memory_utilization_forecast_time_aggregator" { + description = "Time aggregator for the Memory Utilization Forecast monitor" + default = "max" +} + +variable "memory_utilization_forecast_timeframe" { + description = "Timeframe for the Memory Utilization Forecast monitor" + default = "next_3d" +} + +variable "memory_utilization_forecast_algorithm" { + description = "Algorithm for the Memory Utilization Forecast monitor" + type = string + default = "linear" +} + +variable "memory_utilization_forecast_deviations" { + description = "Deviations for the Memory Utilization Forecast monitor" + type = string + default = 1 +} + +variable "memory_utilization_forecast_interval" { + description = "Interval for the Memory Utilization Forecast monitor" + type = string + default = "30m" +} + +variable "memory_utilization_forecast_linear_history" { + description = "History for the Memory Utilization Forecast monitor" + type = string + default = "12h" +} + +variable "memory_utilization_forecast_linear_model" { + description = "Model for the Memory Utilization Forecast monitor" + type = string + default = "default" +} + +variable "memory_utilization_forecast_seasonal_seasonality" { + description = "Seasonality for the Memory Utilization Forecast monitor" + type = string + default = "weekly" +} + +variable "memory_utilization_forecast_threshold_critical" { + description = "Memory Utilization Forecast in percentage (warning threshold)" + default = 90 +} + +variable "memory_utilization_forecast_threshold_critical_recovery" { + description = "Memory Utilization Forecast in percentage (recovery threshold)" + default = 81 +} + +variable "memory_utilization_forecast_enabled" { + description = "Flag to enable GCP Cloud SQL Memory Utilization Forecast monitor" + type = string + default = "false" +} + +variable "memory_utilization_forecast_extra_tags" { + description = "Extra tags for GCP Cloud SQL Memory Utilization Forecast monitor" + type = list(string) + default = [] +} + +# +# Failover Unavailable +# + +variable "failover_unavailable_message" { + description = "Custom message for the Failover Unavailable monitor" + type = string + default = "" +} + +variable "failover_unavailable_time_aggregator" { + description = "Time aggreggator for the Failover Unavailable monitor" + type = string + default = "max" +} + +variable "failover_unavailable_timeframe" { + description = "Timeframe for the Failover Unavailable monitor" + type = string + default = "last_10m" +} + +variable "failover_unavailable_threshold_critical" { + description = "Failover Unavailable critical threshold" + type = string + default = 0 +} + +variable "failover_unavailable_enabled" { + description = "Flag to enable GCP Cloud SQL Failover Unavailable monitor" + type = string + default = "true" +} + +variable "failover_unavailable_extra_tags" { + description = "Extra tags for GCP Cloud SQL Failover Unavailable monitor" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/common/monitors-cloud-sql-common.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/common/monitors-cloud-sql-common.tf new file mode 100755 index 0000000..66c2cac --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/common/monitors-cloud-sql-common.tf @@ -0,0 +1,212 @@ +# +# CPU Utilization +# +resource "datadog_monitor" "cpu_utilization" { + count = var.cpu_utilization_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Cloud SQL CPU Utilization {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cpu_utilization_message, var.message) + type = "query alert" + + query = < ${var.cpu_utilization_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.cpu_utilization_threshold_warning + critical = var.cpu_utilization_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:cloud-sql", "team:claranet", "created-by:terraform"], var.cpu_utilization_extra_tags) +} + +# +# Disk Utilization +# +resource "datadog_monitor" "disk_utilization" { + count = var.disk_utilization_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Cloud SQL Disk Utilization {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.disk_utilization_message, var.message) + type = "query alert" + + query = < ${var.disk_utilization_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.disk_utilization_threshold_warning + critical = var.disk_utilization_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = var.notify_no_data + no_data_timeframe = var.disk_utilization_no_data_timeframe + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:cloud-sql", "team:claranet", "created-by:terraform"], var.disk_utilization_extra_tags) +} + +# +# Disk Utilization Forecast +# +resource "datadog_monitor" "disk_utilization_forecast" { + count = var.disk_utilization_forecast_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Cloud SQL Disk Utilization could reach {{#is_alert}}{{threshold}}%%{{/is_alert}} in a near future" + message = coalesce(var.disk_utilization_forecast_message, var.message) + type = "query alert" + + query = <= ${var.disk_utilization_forecast_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.disk_utilization_forecast_threshold_critical + critical_recovery = var.disk_utilization_forecast_threshold_critical_recovery + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:cloud-sql", "team:claranet", "created-by:terraform"], var.disk_utilization_forecast_extra_tags) +} + +# +# Memory Utilization +# +resource "datadog_monitor" "memory_utilization" { + count = var.memory_utilization_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Cloud SQL Memory Utilization {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.memory_utilization_message, var.message) + type = "query alert" + + query = < ${var.memory_utilization_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.memory_utilization_threshold_warning + critical = var.memory_utilization_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:cloud-sql", "team:claranet", "created-by:terraform"], var.memory_utilization_extra_tags) +} + +# +# Memory Utilization Forecast +# +resource "datadog_monitor" "memory_utilization_forecast" { + count = var.memory_utilization_forecast_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Cloud SQL Memory Utilization could reach {{#is_alert}}{{threshold}}%%{{/is_alert}} in a near future" + message = coalesce(var.memory_utilization_forecast_message, var.message) + type = "query alert" + + query = <= ${var.memory_utilization_forecast_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.memory_utilization_forecast_threshold_critical + critical_recovery = var.memory_utilization_forecast_threshold_critical_recovery + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:cloud-sql", "team:claranet", "created-by:terraform"], var.memory_utilization_forecast_extra_tags) +} + +# +# Failover Unavailable +# +resource "datadog_monitor" "failover_unavailable" { + count = var.failover_unavailable_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Cloud SQL Failover Unavailable" + message = coalesce(var.failover_unavailable_message, var.message) + type = "metric alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.replication_lag](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags](#input\_filter\_tags) | Tags used for filtering | `string` | `"*"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the new host evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [replication\_lag\_enabled](#input\_replication\_lag\_enabled) | Flag to enable GCP Cloud SQL Replication Lag monitor | `string` | `"true"` | no | +| [replication\_lag\_extra\_tags](#input\_replication\_lag\_extra\_tags) | Extra tags for GCP Cloud SQL SQL Replication monitor | `list(string)` | `[]` | no | +| [replication\_lag\_message](#input\_replication\_lag\_message) | Custom message for the Replication Lag monitor | `string` | `""` | no | +| [replication\_lag\_no\_data\_timeframe](#input\_replication\_lag\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `20` | no | +| [replication\_lag\_threshold\_critical](#input\_replication\_lag\_threshold\_critical) | Seconds behind the master (critical threshold) | `string` | `180` | no | +| [replication\_lag\_threshold\_warning](#input\_replication\_lag\_threshold\_warning) | Seconds behind the master (warning threshold) | `string` | `90` | no | +| [replication\_lag\_time\_aggregator](#input\_replication\_lag\_time\_aggregator) | Time aggregator for the Replication Lag monitor | `string` | `"min"` | no | +| [replication\_lag\_timeframe](#input\_replication\_lag\_timeframe) | Timeframe for the Replication Lag monitor | `string` | `"last_10m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [replication\_lag\_id](#output\_replication\_lag\_id) | id for monitor replication\_lag | +## Related documentation + +* [GCP Metrics for CloudSQL](https://cloud.google.com/monitoring/api/metrics_gcp#gcp-cloudsql) +* [Datadog Useful monitors for GCP CloudSQL](https://www.datadoghq.com/blog/monitor-google-cloud-sql/) +* [Max connections depends on the type of the instance](https://cloud.google.com/sql/docs/quotas#fixed-limits) +* [Monitoring Replication Lag](https://cloud.google.com/sql/docs/mysql/high-availability#replication-lag-monitor) +* [Monitoring MySQL Performance Metrics](https://www.datadoghq.com/blog/monitoring-mysql-performance-metrics) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/mysql/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/mysql/inputs.tf new file mode 100755 index 0000000..65cdb43 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/mysql/inputs.tf @@ -0,0 +1,89 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags" { + description = "Tags used for filtering" + default = "*" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds for the new host evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "replication_lag_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 20 +} + +# +# Replication Lag +# + +variable "replication_lag_message" { + description = "Custom message for the Replication Lag monitor" + type = string + default = "" +} + +variable "replication_lag_time_aggregator" { + description = "Time aggregator for the Replication Lag monitor" + type = string + default = "min" +} + +variable "replication_lag_timeframe" { + description = "Timeframe for the Replication Lag monitor" + type = string + default = "last_10m" +} + +variable "replication_lag_threshold_warning" { + description = "Seconds behind the master (warning threshold)" + type = string + default = 90 +} + +variable "replication_lag_threshold_critical" { + description = "Seconds behind the master (critical threshold)" + type = string + default = 180 +} + +variable "replication_lag_enabled" { + description = "Flag to enable GCP Cloud SQL Replication Lag monitor" + type = string + default = "true" +} + +variable "replication_lag_extra_tags" { + description = "Extra tags for GCP Cloud SQL SQL Replication monitor" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/mysql/monitors-cloudsql-mysql.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/mysql/monitors-cloudsql-mysql.tf new file mode 100755 index 0000000..dfa1fcc --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/mysql/monitors-cloudsql-mysql.tf @@ -0,0 +1,34 @@ +# +# Replication Lag +# +resource "datadog_monitor" "replication_lag" { + count = var.replication_lag_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Cloud SQL MySQL Replication Lag {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + message = coalesce(var.replication_lag_message, var.message) + type = "metric alert" + + query = < ${var.replication_lag_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.replication_lag_threshold_critical + warning = var.replication_lag_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = var.notify_no_data + no_data_timeframe = var.replication_lag_no_data_timeframe + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:cloud-sql", "team:claranet", "created-by:terraform", "engine:mysql"], var.replication_lag_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/mysql/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/mysql/outputs.tf new file mode 100755 index 0000000..3134033 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/mysql/outputs.tf @@ -0,0 +1,5 @@ +output "replication_lag_id" { + description = "id for monitor replication_lag" + value = datadog_monitor.replication_lag.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/mysql/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/mysql/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/cloud-sql/mysql/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/gce/instance/MANIFEST.txt b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/gce/instance/MANIFEST.txt new file mode 100755 index 0000000..6de6b50 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/gce/instance/MANIFEST.txt @@ -0,0 +1 @@ +cloud-gcp diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/gce/instance/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/gce/instance/README.md new file mode 100755 index 0000000..45e4112 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/gce/instance/README.md @@ -0,0 +1,93 @@ +# CLOUD GCP GCE INSTANCE DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-gcp-gce-instance" { + source = "claranet/monitors/datadog//cloud/gcp/gce/instance" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Compute Engine instance CPU Utilization +- Compute Engine instance Disk Throttled Bps +- Compute Engine instance Disk Throttled OPS + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cpu_utilization](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.disk_throttled_bps](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.disk_throttled_ops](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_utilization\_enabled](#input\_cpu\_utilization\_enabled) | Flag to enable CPU Utilization monitor | `string` | `"true"` | no | +| [cpu\_utilization\_extra\_tags](#input\_cpu\_utilization\_extra\_tags) | Extra tags for CPU Utilization monitor | `list(string)` | `[]` | no | +| [cpu\_utilization\_message](#input\_cpu\_utilization\_message) | Custom message for the CPU Utilization monitor | `string` | `""` | no | +| [cpu\_utilization\_no\_data\_timeframe](#input\_cpu\_utilization\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `30` | no | +| [cpu\_utilization\_threshold\_critical](#input\_cpu\_utilization\_threshold\_critical) | CPU Utilization in percentage (critical threshold) | `string` | `90` | no | +| [cpu\_utilization\_threshold\_warning](#input\_cpu\_utilization\_threshold\_warning) | CPU Utilization in percentage (warning threshold) | `string` | `80` | no | +| [cpu\_utilization\_time\_aggregator](#input\_cpu\_utilization\_time\_aggregator) | Time aggregator for the CPU Utilization monitor | `string` | `"avg"` | no | +| [cpu\_utilization\_timeframe](#input\_cpu\_utilization\_timeframe) | Timeframe for the CPU Utilization monitor | `string` | `"last_15m"` | no | +| [disk\_throttled\_bps\_enabled](#input\_disk\_throttled\_bps\_enabled) | Flag to enable Disk Throttled Bps monitor | `string` | `"true"` | no | +| [disk\_throttled\_bps\_extra\_tags](#input\_disk\_throttled\_bps\_extra\_tags) | Extra tags for Disk Throttled Bps monitor | `list(string)` | `[]` | no | +| [disk\_throttled\_bps\_message](#input\_disk\_throttled\_bps\_message) | Custom message for the Disk Throttled Bps monitor | `string` | `""` | no | +| [disk\_throttled\_bps\_threshold\_critical](#input\_disk\_throttled\_bps\_threshold\_critical) | Disk Throttled Bps in percentage (critical threshold) | `string` | `50` | no | +| [disk\_throttled\_bps\_threshold\_warning](#input\_disk\_throttled\_bps\_threshold\_warning) | Disk Throttled Bps in percentage (warning threshold) | `string` | `30` | no | +| [disk\_throttled\_bps\_time\_aggregator](#input\_disk\_throttled\_bps\_time\_aggregator) | Time aggregator for the Disk Throttled Bps monitor | `string` | `"min"` | no | +| [disk\_throttled\_bps\_timeframe](#input\_disk\_throttled\_bps\_timeframe) | Timeframe for the Disk Throttled Bps monitor | `string` | `"last_15m"` | no | +| [disk\_throttled\_ops\_enabled](#input\_disk\_throttled\_ops\_enabled) | Flag to enable Disk Throttled OPS monitor | `string` | `"true"` | no | +| [disk\_throttled\_ops\_extra\_tags](#input\_disk\_throttled\_ops\_extra\_tags) | Extra tags for Disk Throttled OPS monitor | `list(string)` | `[]` | no | +| [disk\_throttled\_ops\_message](#input\_disk\_throttled\_ops\_message) | Custom message for the Disk Throttled OPS monitor | `string` | `""` | no | +| [disk\_throttled\_ops\_threshold\_critical](#input\_disk\_throttled\_ops\_threshold\_critical) | Disk Throttled OPS in percentage (critical threshold) | `string` | `50` | no | +| [disk\_throttled\_ops\_threshold\_warning](#input\_disk\_throttled\_ops\_threshold\_warning) | Disk Throttled OPS in percentage (warning threshold) | `string` | `30` | no | +| [disk\_throttled\_ops\_time\_aggregator](#input\_disk\_throttled\_ops\_time\_aggregator) | Time aggregator for the Disk Throttled OPS monitor | `string` | `"min"` | no | +| [disk\_throttled\_ops\_timeframe](#input\_disk\_throttled\_ops\_timeframe) | Timeframe for the Disk Throttled OPS monitor | `string` | `"last_15m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags](#input\_filter\_tags) | Tags used for filtering | `string` | `"*"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the new host evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cpu\_utilization\_id](#output\_cpu\_utilization\_id) | id for monitor cpu\_utilization | +| [disk\_throttled\_bps\_id](#output\_disk\_throttled\_bps\_id) | id for monitor disk\_throttled\_bps | +| [disk\_throttled\_ops\_id](#output\_disk\_throttled\_ops\_id) | id for monitor disk\_throttled\_ops | +## Related documentation + +* [Datadog GCE Instance metrics](https://www.datadoghq.com/blog/monitoring-google-compute-engine-performance/#instance-metrics) +* [GCP Maximum OPS and Bps by device type and size](https://cloud.google.com/compute/docs/disks/) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/gce/instance/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/gce/instance/inputs.tf new file mode 100755 index 0000000..893db24 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/gce/instance/inputs.tf @@ -0,0 +1,181 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags" { + description = "Tags used for filtering" + default = "*" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds for the new host evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "cpu_utilization_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 30 +} + +# +# CPU +# + +variable "cpu_utilization_message" { + description = "Custom message for the CPU Utilization monitor" + type = string + default = "" +} + +variable "cpu_utilization_time_aggregator" { + description = "Time aggregator for the CPU Utilization monitor" + type = string + default = "avg" +} + +variable "cpu_utilization_timeframe" { + description = "Timeframe for the CPU Utilization monitor" + type = string + default = "last_15m" +} + +variable "cpu_utilization_threshold_warning" { + description = "CPU Utilization in percentage (warning threshold)" + type = string + default = 80 +} + +variable "cpu_utilization_threshold_critical" { + description = "CPU Utilization in percentage (critical threshold)" + type = string + default = 90 +} + +variable "cpu_utilization_enabled" { + description = "Flag to enable CPU Utilization monitor" + type = string + default = "true" +} + +variable "cpu_utilization_extra_tags" { + description = "Extra tags for CPU Utilization monitor" + type = list(string) + default = [] +} + +# +# Disk Throttled Bps +# + +variable "disk_throttled_bps_message" { + description = "Custom message for the Disk Throttled Bps monitor" + type = string + default = "" +} + +variable "disk_throttled_bps_time_aggregator" { + description = "Time aggregator for the Disk Throttled Bps monitor" + type = string + default = "min" +} + +variable "disk_throttled_bps_timeframe" { + description = "Timeframe for the Disk Throttled Bps monitor" + type = string + default = "last_15m" +} + +variable "disk_throttled_bps_threshold_warning" { + description = "Disk Throttled Bps in percentage (warning threshold)" + type = string + default = 30 +} + +variable "disk_throttled_bps_threshold_critical" { + description = "Disk Throttled Bps in percentage (critical threshold)" + type = string + default = 50 +} + +variable "disk_throttled_bps_enabled" { + description = "Flag to enable Disk Throttled Bps monitor" + type = string + default = "true" +} + +variable "disk_throttled_bps_extra_tags" { + description = "Extra tags for Disk Throttled Bps monitor" + type = list(string) + default = [] +} + +# +# Disk Throttled OPS +# + +variable "disk_throttled_ops_message" { + description = "Custom message for the Disk Throttled OPS monitor" + type = string + default = "" +} + +variable "disk_throttled_ops_time_aggregator" { + description = "Time aggregator for the Disk Throttled OPS monitor" + type = string + default = "min" +} + +variable "disk_throttled_ops_timeframe" { + description = "Timeframe for the Disk Throttled OPS monitor" + type = string + default = "last_15m" +} + +variable "disk_throttled_ops_threshold_warning" { + description = "Disk Throttled OPS in percentage (warning threshold)" + type = string + default = 30 +} + +variable "disk_throttled_ops_threshold_critical" { + description = "Disk Throttled OPS in percentage (critical threshold)" + type = string + default = 50 +} + +variable "disk_throttled_ops_enabled" { + description = "Flag to enable Disk Throttled OPS monitor" + type = string + default = "true" +} + +variable "disk_throttled_ops_extra_tags" { + description = "Extra tags for Disk Throttled OPS monitor" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/gce/instance/monitors-gce-instance.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/gce/instance/monitors-gce-instance.tf new file mode 100755 index 0000000..cf9c721 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/gce/instance/monitors-gce-instance.tf @@ -0,0 +1,112 @@ +# +# CPU Utilization +# +resource "datadog_monitor" "cpu_utilization" { + count = var.cpu_utilization_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Compute Engine instance CPU Utilization {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cpu_utilization_message, var.message) + type = "query alert" + + query = < ${var.cpu_utilization_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.cpu_utilization_threshold_warning + critical = var.cpu_utilization_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = var.notify_no_data + no_data_timeframe = var.cpu_utilization_no_data_timeframe + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:gce-instance", "team:claranet", "created-by:terraform"], var.cpu_utilization_extra_tags) +} + +# +# Disk Throttled Bps +# +resource "datadog_monitor" "disk_throttled_bps" { + count = var.disk_throttled_bps_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Compute Engine instance Disk Throttled Bps {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.disk_throttled_bps_message, var.message) + type = "query alert" + + query = < ${var.disk_throttled_bps_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.disk_throttled_bps_threshold_warning + critical = var.disk_throttled_bps_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:gce-instance", "team:claranet", "created-by:terraform"], var.disk_throttled_bps_extra_tags) +} + +# +# Disk Throttled OPS +# +resource "datadog_monitor" "disk_throttled_ops" { + count = var.disk_throttled_ops_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Compute Engine instance Disk Throttled OPS {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.disk_throttled_ops_message, var.message) + type = "query alert" + + query = < ${var.disk_throttled_ops_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.disk_throttled_ops_threshold_warning + critical = var.disk_throttled_ops_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:gce-instance", "team:claranet", "created-by:terraform"], var.disk_throttled_ops_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/gce/instance/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/gce/instance/outputs.tf new file mode 100755 index 0000000..002b395 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/gce/instance/outputs.tf @@ -0,0 +1,15 @@ +output "cpu_utilization_id" { + description = "id for monitor cpu_utilization" + value = datadog_monitor.cpu_utilization.*.id +} + +output "disk_throttled_bps_id" { + description = "id for monitor disk_throttled_bps" + value = datadog_monitor.disk_throttled_bps.*.id +} + +output "disk_throttled_ops_id" { + description = "id for monitor disk_throttled_ops" + value = datadog_monitor.disk_throttled_ops.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/gce/instance/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/gce/instance/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/gce/instance/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/lb/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/lb/README.md new file mode 100755 index 0000000..1fdd8d5 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/lb/README.md @@ -0,0 +1,115 @@ +# CLOUD GCP LB DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-gcp-lb" { + source = "claranet/monitors/datadog//cloud/gcp/lb" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- GCP LB 4xx errors +- GCP LB 5xx errors +- GCP LB bucket backend latency +- GCP LB Requests count increased abruptly +- GCP LB service backend latency + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.backend_latency_bucket](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.backend_latency_service](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.error_rate_4xx](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.error_rate_5xx](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.request_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [backend\_latency\_bucket\_enabled](#input\_backend\_latency\_bucket\_enabled) | Flag to enable GCP LB Backend Latency monitor | `string` | `"true"` | no | +| [backend\_latency\_bucket\_extra\_tags](#input\_backend\_latency\_bucket\_extra\_tags) | Extra tags for GCP LB Backend Latency monitor | `list(string)` | `[]` | no | +| [backend\_latency\_bucket\_message](#input\_backend\_latency\_bucket\_message) | Custom message for the GCP LB Backend Latency monitor | `string` | `""` | no | +| [backend\_latency\_bucket\_threshold\_critical](#input\_backend\_latency\_bucket\_threshold\_critical) | Latency in milliseconds (critical threshold) | `string` | `8000` | no | +| [backend\_latency\_bucket\_threshold\_warning](#input\_backend\_latency\_bucket\_threshold\_warning) | Latency in milliseconds (warning threshold) | `string` | `4000` | no | +| [backend\_latency\_bucket\_time\_aggregator](#input\_backend\_latency\_bucket\_time\_aggregator) | Timeframe for the GCP LB Backend Latency monitor | `string` | `"min"` | no | +| [backend\_latency\_bucket\_timeframe](#input\_backend\_latency\_bucket\_timeframe) | Timeframe for the GCP LB Backend Latency monitor | `string` | `"last_10m"` | no | +| [backend\_latency\_service\_enabled](#input\_backend\_latency\_service\_enabled) | Flag to enable GCP LB Backend Latency monitor | `string` | `"true"` | no | +| [backend\_latency\_service\_extra\_tags](#input\_backend\_latency\_service\_extra\_tags) | Extra tags for GCP LB Backend Latency monitor | `list(string)` | `[]` | no | +| [backend\_latency\_service\_message](#input\_backend\_latency\_service\_message) | Custom message for the GCP LB Backend Latency monitor | `string` | `""` | no | +| [backend\_latency\_service\_threshold\_critical](#input\_backend\_latency\_service\_threshold\_critical) | Latency in milliseconds (critical threshold) | `string` | `1500` | no | +| [backend\_latency\_service\_threshold\_warning](#input\_backend\_latency\_service\_threshold\_warning) | Latency in milliseconds (warning threshold) | `string` | `1000` | no | +| [backend\_latency\_service\_time\_aggregator](#input\_backend\_latency\_service\_time\_aggregator) | Timeframe for the GCP LB Backend Latency monitor | `string` | `"min"` | no | +| [backend\_latency\_service\_timeframe](#input\_backend\_latency\_service\_timeframe) | Timeframe for the GCP LB Backend Latency monitor | `string` | `"last_10m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [error\_rate\_4xx\_artificial\_request](#input\_error\_rate\_4xx\_artificial\_request) | Divisor Delta for the GCP LB 4XX Errors monitor | `string` | `5` | no | +| [error\_rate\_4xx\_enabled](#input\_error\_rate\_4xx\_enabled) | Flag to enable GCP LB 4XX Errors monitor | `string` | `"true"` | no | +| [error\_rate\_4xx\_extra\_tags](#input\_error\_rate\_4xx\_extra\_tags) | Extra tags for GCP LB 4XX Errors monitor | `list(string)` | `[]` | no | +| [error\_rate\_4xx\_message](#input\_error\_rate\_4xx\_message) | Custom message for the GCP LB 4XX Errors monitor | `string` | `""` | no | +| [error\_rate\_4xx\_threshold\_critical](#input\_error\_rate\_4xx\_threshold\_critical) | Rate error in percentage (critical threshold) | `string` | `60` | no | +| [error\_rate\_4xx\_threshold\_warning](#input\_error\_rate\_4xx\_threshold\_warning) | Rate error in percentage (warning threshold) | `string` | `50` | no | +| [error\_rate\_4xx\_time\_aggregator](#input\_error\_rate\_4xx\_time\_aggregator) | Timeframe for the GCP LB 4XX Errors monitor | `string` | `"min"` | no | +| [error\_rate\_4xx\_timeframe](#input\_error\_rate\_4xx\_timeframe) | Timeframe for the GCP LB 4XX Errors monitor | `string` | `"last_5m"` | no | +| [error\_rate\_5xx\_artificial\_request](#input\_error\_rate\_5xx\_artificial\_request) | Divisor Delta for the GCP LB 5XX Errors monitor | `string` | `5` | no | +| [error\_rate\_5xx\_enabled](#input\_error\_rate\_5xx\_enabled) | Flag to enable GCP LB 5XX Errors monitor | `string` | `"true"` | no | +| [error\_rate\_5xx\_extra\_tags](#input\_error\_rate\_5xx\_extra\_tags) | Extra tags for GCP LB 5XX Errors monitor | `list(string)` | `[]` | no | +| [error\_rate\_5xx\_message](#input\_error\_rate\_5xx\_message) | Custom message for the GCP LB 5XX Errors monitor | `string` | `""` | no | +| [error\_rate\_5xx\_threshold\_critical](#input\_error\_rate\_5xx\_threshold\_critical) | Rate error in percentage (critical threshold) | `string` | `40` | no | +| [error\_rate\_5xx\_threshold\_warning](#input\_error\_rate\_5xx\_threshold\_warning) | Rate error in percentage (warning threshold) | `string` | `30` | no | +| [error\_rate\_5xx\_time\_aggregator](#input\_error\_rate\_5xx\_time\_aggregator) | Timeframe for the GCP LB 5XX Errors monitor | `string` | `"min"` | no | +| [error\_rate\_5xx\_timeframe](#input\_error\_rate\_5xx\_timeframe) | Timeframe for the GCP LB 5XX Errors monitor | `string` | `"last_5m"` | no | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags](#input\_filter\_tags) | Tags used for filtering | `string` | `"*"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the new host evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [request\_count\_enabled](#input\_request\_count\_enabled) | Flag to enable GCP LB Request Count monitor | `string` | `"true"` | no | +| [request\_count\_extra\_tags](#input\_request\_count\_extra\_tags) | Extra tags for GCP LB Request Count monitor | `list(string)` | `[]` | no | +| [request\_count\_message](#input\_request\_count\_message) | Custom message for the GCP LB Request Count monitor | `string` | `""` | no | +| [request\_count\_threshold\_critical](#input\_request\_count\_threshold\_critical) | Desviation in percentage (critical threshold) | `string` | `500` | no | +| [request\_count\_threshold\_warning](#input\_request\_count\_threshold\_warning) | Desviation in percentage (warning threshold) | `string` | `250` | no | +| [request\_count\_time\_aggregator](#input\_request\_count\_time\_aggregator) | Timeframe for the GCP LB Request Count monitor | `string` | `"sum"` | no | +| [request\_count\_timeframe](#input\_request\_count\_timeframe) | Timeframe for the GCP LB Request Count monitor | `string` | `"last_5m"` | no | +| [request\_count\_timeshift](#input\_request\_count\_timeshift) | Timeshift for the GCP LB Request Count monitor | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [backend\_latency\_bucket\_id](#output\_backend\_latency\_bucket\_id) | id for monitor backend\_latency\_bucket | +| [backend\_latency\_service\_id](#output\_backend\_latency\_service\_id) | id for monitor backend\_latency\_service | +| [error\_rate\_4xx\_id](#output\_error\_rate\_4xx\_id) | id for monitor error\_rate\_4xx | +| [error\_rate\_5xx\_id](#output\_error\_rate\_5xx\_id) | id for monitor error\_rate\_5xx | +| [request\_count\_id](#output\_request\_count\_id) | id for monitor request\_count | +## Related documentation + +* [GCP LB Metrics](https://cloud.google.com/monitoring/api/metrics_gcp#gcp-loadbalancing) +* [Datadog GCP integration](https://docs.datadoghq.com/integrations/google_cloud_platform/) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/lb/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/lb/inputs.tf new file mode 100755 index 0000000..1009608 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/lb/inputs.tf @@ -0,0 +1,280 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags" { + description = "Tags used for filtering" + default = "*" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds for the new host evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# +# 4XX Errors +# +variable "error_rate_4xx_message" { + description = "Custom message for the GCP LB 4XX Errors monitor" + type = string + default = "" +} + +variable "error_rate_4xx_time_aggregator" { + description = "Timeframe for the GCP LB 4XX Errors monitor" + type = string + default = "min" +} + +variable "error_rate_4xx_timeframe" { + description = "Timeframe for the GCP LB 4XX Errors monitor" + type = string + default = "last_5m" +} + +variable "error_rate_4xx_artificial_request" { + description = "Divisor Delta for the GCP LB 4XX Errors monitor" + type = string + default = 5 +} + +variable "error_rate_4xx_threshold_warning" { + description = "Rate error in percentage (warning threshold)" + type = string + default = 50 +} + +variable "error_rate_4xx_threshold_critical" { + description = "Rate error in percentage (critical threshold)" + type = string + default = 60 +} + +variable "error_rate_4xx_enabled" { + description = "Flag to enable GCP LB 4XX Errors monitor" + type = string + default = "true" +} + +variable "error_rate_4xx_extra_tags" { + description = "Extra tags for GCP LB 4XX Errors monitor" + type = list(string) + default = [] +} + +# +# 5XX Errors +# +variable "error_rate_5xx_message" { + description = "Custom message for the GCP LB 5XX Errors monitor" + type = string + default = "" +} + +variable "error_rate_5xx_time_aggregator" { + description = "Timeframe for the GCP LB 5XX Errors monitor" + type = string + default = "min" +} + +variable "error_rate_5xx_timeframe" { + description = "Timeframe for the GCP LB 5XX Errors monitor" + type = string + default = "last_5m" +} + +variable "error_rate_5xx_artificial_request" { + description = "Divisor Delta for the GCP LB 5XX Errors monitor" + type = string + default = 5 +} + +variable "error_rate_5xx_threshold_warning" { + description = "Rate error in percentage (warning threshold)" + type = string + default = 30 +} + +variable "error_rate_5xx_threshold_critical" { + description = "Rate error in percentage (critical threshold)" + type = string + default = 40 +} + +variable "error_rate_5xx_enabled" { + description = "Flag to enable GCP LB 5XX Errors monitor" + type = string + default = "true" +} + +variable "error_rate_5xx_extra_tags" { + description = "Extra tags for GCP LB 5XX Errors monitor" + type = list(string) + default = [] +} + +# +# Latency Backend service +# +variable "backend_latency_service_message" { + description = "Custom message for the GCP LB Backend Latency monitor" + type = string + default = "" +} + +variable "backend_latency_service_time_aggregator" { + description = "Timeframe for the GCP LB Backend Latency monitor" + type = string + default = "min" +} + +variable "backend_latency_service_timeframe" { + description = "Timeframe for the GCP LB Backend Latency monitor" + type = string + default = "last_10m" +} + +variable "backend_latency_service_threshold_warning" { + description = "Latency in milliseconds (warning threshold)" + type = string + default = 1000 +} + +variable "backend_latency_service_threshold_critical" { + description = "Latency in milliseconds (critical threshold)" + type = string + default = 1500 +} + +variable "backend_latency_service_enabled" { + description = "Flag to enable GCP LB Backend Latency monitor" + type = string + default = "true" +} + +variable "backend_latency_service_extra_tags" { + description = "Extra tags for GCP LB Backend Latency monitor" + type = list(string) + default = [] +} + +# +# Latency Backend bucket +# +variable "backend_latency_bucket_message" { + description = "Custom message for the GCP LB Backend Latency monitor" + type = string + default = "" +} + +variable "backend_latency_bucket_time_aggregator" { + description = "Timeframe for the GCP LB Backend Latency monitor" + type = string + default = "min" +} + +variable "backend_latency_bucket_timeframe" { + description = "Timeframe for the GCP LB Backend Latency monitor" + type = string + default = "last_10m" +} + +variable "backend_latency_bucket_threshold_warning" { + description = "Latency in milliseconds (warning threshold)" + type = string + default = 4000 +} + +variable "backend_latency_bucket_threshold_critical" { + description = "Latency in milliseconds (critical threshold)" + type = string + default = 8000 +} + +variable "backend_latency_bucket_enabled" { + description = "Flag to enable GCP LB Backend Latency monitor" + type = string + default = "true" +} + +variable "backend_latency_bucket_extra_tags" { + description = "Extra tags for GCP LB Backend Latency monitor" + type = list(string) + default = [] +} + +# +# Request Count +# +variable "request_count_message" { + description = "Custom message for the GCP LB Request Count monitor" + type = string + default = "" +} + +variable "request_count_time_aggregator" { + description = "Timeframe for the GCP LB Request Count monitor" + type = string + default = "sum" +} + +variable "request_count_timeframe" { + description = "Timeframe for the GCP LB Request Count monitor" + type = string + default = "last_5m" +} + +variable "request_count_timeshift" { + description = "Timeshift for the GCP LB Request Count monitor" + type = string + default = "last_5m" +} + +variable "request_count_threshold_warning" { + description = "Desviation in percentage (warning threshold)" + type = string + default = 250 +} + +variable "request_count_threshold_critical" { + description = "Desviation in percentage (critical threshold)" + type = string + default = 500 +} + +variable "request_count_enabled" { + description = "Flag to enable GCP LB Request Count monitor" + type = string + default = "true" +} + +variable "request_count_extra_tags" { + description = "Extra tags for GCP LB Request Count monitor" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/lb/monitors-lb.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/lb/monitors-lb.tf new file mode 100755 index 0000000..6dae71d --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/lb/monitors-lb.tf @@ -0,0 +1,167 @@ +# +# 4XX Errors +# +resource "datadog_monitor" "error_rate_4xx" { + count = var.error_rate_4xx_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP LB 4xx errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.error_rate_4xx_message, var.message) + type = "query alert" + + query = < ${var.error_rate_4xx_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.error_rate_4xx_threshold_warning + critical = var.error_rate_4xx_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:lb", "team:claranet", "created-by:terraform"], var.error_rate_4xx_extra_tags) +} + +# +# 5XX Errors +# +resource "datadog_monitor" "error_rate_5xx" { + count = var.error_rate_5xx_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP LB 5xx errors {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.error_rate_5xx_message, var.message) + type = "query alert" + + query = < ${var.error_rate_5xx_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.error_rate_5xx_threshold_warning + critical = var.error_rate_5xx_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:lb", "team:claranet", "created-by:terraform"], var.error_rate_5xx_extra_tags) +} + +# +# Backend Latency for service +# +resource "datadog_monitor" "backend_latency_service" { + count = var.backend_latency_service_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP LB service backend latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.backend_latency_service_message, var.message) + type = "query alert" + + query = < ${var.backend_latency_service_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.backend_latency_service_threshold_warning + critical = var.backend_latency_service_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:lb", "team:claranet", "created-by:terraform"], var.backend_latency_service_extra_tags) +} + +# +# Backend Latency for bucket +# +resource "datadog_monitor" "backend_latency_bucket" { + count = var.backend_latency_bucket_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP LB bucket backend latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.backend_latency_bucket_message, var.message) + type = "query alert" + + query = < ${var.backend_latency_bucket_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.backend_latency_bucket_threshold_warning + critical = var.backend_latency_bucket_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:lb", "team:claranet", "created-by:terraform"], var.backend_latency_bucket_extra_tags) +} + +# +# Request Count +# +resource "datadog_monitor" "request_count" { + count = var.request_count_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] GCP LB Requests count increased abruptly {{#is_alert}}{{value}}%%{{/is_alert}}{{#is_warning}}{{value}}%%{{/is_warning}}" + message = coalesce(var.request_count_message, var.message) + type = "query alert" + + query = < ${var.request_count_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.request_count_threshold_warning + critical = var.request_count_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:lb", "team:claranet", "created-by:terraform"], var.request_count_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/lb/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/lb/outputs.tf new file mode 100755 index 0000000..27a0d60 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/lb/outputs.tf @@ -0,0 +1,25 @@ +output "backend_latency_bucket_id" { + description = "id for monitor backend_latency_bucket" + value = datadog_monitor.backend_latency_bucket.*.id +} + +output "backend_latency_service_id" { + description = "id for monitor backend_latency_service" + value = datadog_monitor.backend_latency_service.*.id +} + +output "error_rate_4xx_id" { + description = "id for monitor error_rate_4xx" + value = datadog_monitor.error_rate_4xx.*.id +} + +output "error_rate_5xx_id" { + description = "id for monitor error_rate_5xx" + value = datadog_monitor.error_rate_5xx.*.id +} + +output "request_count_id" { + description = "id for monitor request_count" + value = datadog_monitor.request_count.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/lb/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/lb/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/lb/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/memorystore/redis/MANIFEST.txt b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/memorystore/redis/MANIFEST.txt new file mode 100755 index 0000000..6de6b50 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/memorystore/redis/MANIFEST.txt @@ -0,0 +1 @@ +cloud-gcp diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/memorystore/redis/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/memorystore/redis/README.md new file mode 100755 index 0000000..737c1a5 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/memorystore/redis/README.md @@ -0,0 +1,75 @@ +# CLOUD GCP MEMORYSTORE REDIS DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-gcp-memorystore-redis" { + source = "claranet/monitors/datadog//cloud/gcp/memorystore/redis" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Memorystore Redis system memory usage ratio + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.system_memory_usage_ratio](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags](#input\_filter\_tags) | Tags used for filtering | `string` | `"*"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the new host evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [system\_memory\_usage\_ratio\_enabled](#input\_system\_memory\_usage\_ratio\_enabled) | Flag to enable GCP Memorystore Redis System memory usage ratio monitor | `string` | `"true"` | no | +| [system\_memory\_usage\_ratio\_extra\_tags](#input\_system\_memory\_usage\_ratio\_extra\_tags) | Extra tags for GCP Memorystore Redis System memory usage ratio monitor | `list(string)` | `[]` | no | +| [system\_memory\_usage\_ratio\_message](#input\_system\_memory\_usage\_ratio\_message) | Custom message for Memorystore Redis System memory usage ratio monitor | `string` | `""` | no | +| [system\_memory\_usage\_ratio\_no\_data\_timeframe](#input\_system\_memory\_usage\_ratio\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `20` | no | +| [system\_memory\_usage\_ratio\_threshold\_critical](#input\_system\_memory\_usage\_ratio\_threshold\_critical) | Memorystore Redis System memory usage ratio critical threshold | `string` | `90` | no | +| [system\_memory\_usage\_ratio\_threshold\_warning](#input\_system\_memory\_usage\_ratio\_threshold\_warning) | Memorystore Redis System memory usage ratio warning threshold | `string` | `80` | no | +| [system\_memory\_usage\_ratio\_time\_aggregator](#input\_system\_memory\_usage\_ratio\_time\_aggregator) | Time aggregator for Memorystore Redis System memory usage ratio monitor | `string` | `"min"` | no | +| [system\_memory\_usage\_ratio\_timeframe](#input\_system\_memory\_usage\_ratio\_timeframe) | Timeframe for Memorystore Redis System memory usage ratio monitor | `string` | `"last_10m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [system\_memory\_usage\_ratio\_id](#output\_system\_memory\_usage\_ratio\_id) | id for monitor system\_memory\_usage\_ratio | +## Related documentation + +* [GCP Metrics for Memorystore Redis](https://cloud.google.com/monitoring/api/metrics_gcp#gcp-redis) +* [Datadog integration for GCP Memorystore Redis](https://docs.datadoghq.com/integrations/google_cloud_redis/) +* [Memory management best practices](https://cloud.google.com/memorystore/docs/redis/memory-management-best-practices#monitor_your_instances_memory_usage) +* [Monitoring System memory usage ratio](https://cloud.google.com/memorystore/docs/redis/memory-management-best-practices#system_memory_usage_ratio_2) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/memorystore/redis/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/memorystore/redis/inputs.tf new file mode 100755 index 0000000..b952d15 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/memorystore/redis/inputs.tf @@ -0,0 +1,89 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags" { + description = "Tags used for filtering" + default = "*" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds for the new host evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "system_memory_usage_ratio_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 20 +} + +# +# System memory usage ratio +# + +variable "system_memory_usage_ratio_message" { + description = "Custom message for Memorystore Redis System memory usage ratio monitor" + type = string + default = "" +} + +variable "system_memory_usage_ratio_time_aggregator" { + description = "Time aggregator for Memorystore Redis System memory usage ratio monitor" + type = string + default = "min" +} + +variable "system_memory_usage_ratio_timeframe" { + description = "Timeframe for Memorystore Redis System memory usage ratio monitor" + type = string + default = "last_10m" +} + +variable "system_memory_usage_ratio_threshold_warning" { + description = "Memorystore Redis System memory usage ratio warning threshold" + type = string + default = 80 +} + +variable "system_memory_usage_ratio_threshold_critical" { + description = "Memorystore Redis System memory usage ratio critical threshold" + type = string + default = 90 +} + +variable "system_memory_usage_ratio_enabled" { + description = "Flag to enable GCP Memorystore Redis System memory usage ratio monitor" + type = string + default = "true" +} + +variable "system_memory_usage_ratio_extra_tags" { + description = "Extra tags for GCP Memorystore Redis System memory usage ratio monitor" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/memorystore/redis/monitors-memorystore-redis.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/memorystore/redis/monitors-memorystore-redis.tf new file mode 100755 index 0000000..78708a7 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/memorystore/redis/monitors-memorystore-redis.tf @@ -0,0 +1,33 @@ +# +# System memory usage ratio +# +resource "datadog_monitor" "system_memory_usage_ratio" { + count = var.system_memory_usage_ratio_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Memorystore Redis system memory usage ratio {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + message = coalesce(var.system_memory_usage_ratio_message, var.message) + type = "metric alert" + + query = < ${var.system_memory_usage_ratio_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.system_memory_usage_ratio_threshold_critical + warning = var.system_memory_usage_ratio_threshold_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = var.notify_no_data + no_data_timeframe = var.system_memory_usage_ratio_no_data_timeframe + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:memorystore", "team:claranet", "created-by:terraform", "engine:redis"], var.system_memory_usage_ratio_extra_tags) +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/memorystore/redis/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/memorystore/redis/outputs.tf new file mode 100755 index 0000000..4ea39c1 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/memorystore/redis/outputs.tf @@ -0,0 +1,5 @@ +output "system_memory_usage_ratio_id" { + description = "id for monitor system_memory_usage_ratio" + value = datadog_monitor.system_memory_usage_ratio.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/memorystore/redis/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/memorystore/redis/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/memorystore/redis/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/subscription/MANIFEST.txt b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/subscription/MANIFEST.txt new file mode 100755 index 0000000..6de6b50 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/subscription/MANIFEST.txt @@ -0,0 +1 @@ +cloud-gcp diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/subscription/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/subscription/README.md new file mode 100755 index 0000000..60990bf --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/subscription/README.md @@ -0,0 +1,98 @@ +# CLOUD GCP PUBSUB SUBSCRIPTION DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-gcp-pubsub-subscription" { + source = "claranet/monitors/datadog//cloud/gcp/pubsub/subscription" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Pub/Sub Subscription latency on push endpoint +- Pub/Sub Subscription latency on push endpoint changed abnormally (disabled by default) +- Pub/Sub Subscription oldest unacknowledged message + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.oldest_unacked_message_age](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.subscription_push_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.subscription_push_latency_anomaly](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags](#input\_filter\_tags) | Tags used for filtering | `string` | `"*"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the new host evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [oldest\_unacked\_message\_age\_enabled](#input\_oldest\_unacked\_message\_age\_enabled) | Flag to enable GCP Pub/Sub Subscription Oldest Unacked Message Age monitor | `string` | `"true"` | no | +| [oldest\_unacked\_message\_age\_extra\_tags](#input\_oldest\_unacked\_message\_age\_extra\_tags) | Extra tags for GCP Pub/Sub Subscription Oldest Unacked Message Age monitor | `list(string)` | `[]` | no | +| [oldest\_unacked\_message\_age\_message](#input\_oldest\_unacked\_message\_age\_message) | Custom message for the GCP Pub/Sub Subscription Oldest Unacked Message Age monitor | `string` | `""` | no | +| [oldest\_unacked\_message\_age\_threshold\_critical](#input\_oldest\_unacked\_message\_age\_threshold\_critical) | GCP Pub/Sub Subscription Oldest Unacked Message Age critical threshold | `string` | `120` | no | +| [oldest\_unacked\_message\_age\_threshold\_warning](#input\_oldest\_unacked\_message\_age\_threshold\_warning) | GCP Pub/Sub Subscription Oldest Unacked Message Age warning threshold | `string` | `30` | no | +| [oldest\_unacked\_message\_age\_time\_aggregator](#input\_oldest\_unacked\_message\_age\_time\_aggregator) | Time aggregator for the GCP Pub/Sub Subscription Oldest Unacked Message Age monitor | `string` | `"min"` | no | +| [oldest\_unacked\_message\_age\_timeframe](#input\_oldest\_unacked\_message\_age\_timeframe) | Timeframe for the GCP Pub/Sub Subscription Oldest Unacked Message Age monitor | `string` | `"last_5m"` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [subscription\_push\_latency\_anomaly\_alert\_window](#input\_subscription\_push\_latency\_anomaly\_alert\_window) | Alert window. | `string` | `"last_15m"` | no | +| [subscription\_push\_latency\_anomaly\_count\_default\_zero](#input\_subscription\_push\_latency\_anomaly\_count\_default\_zero) | Count default zero. | `string` | `"true"` | no | +| [subscription\_push\_latency\_anomaly\_detection\_algorithm](#input\_subscription\_push\_latency\_anomaly\_detection\_algorithm) | Anomaly Detection Algorithm used | `string` | `"basic"` | no | +| [subscription\_push\_latency\_anomaly\_direction](#input\_subscription\_push\_latency\_anomaly\_direction) | Direction of the anomaly. It can be both, below or above. | `string` | `"above"` | no | +| [subscription\_push\_latency\_anomaly\_enabled](#input\_subscription\_push\_latency\_anomaly\_enabled) | Flag to enable GCP Pub/Sub Subscription Push Latency Anomaly monitor | `string` | `"false"` | no | +| [subscription\_push\_latency\_anomaly\_extra\_tags](#input\_subscription\_push\_latency\_anomaly\_extra\_tags) | Extra tags for GCP Pub/Sub Subscription Push Latency Anomaly monitor | `list(string)` | `[]` | no | +| [subscription\_push\_latency\_anomaly\_interval](#input\_subscription\_push\_latency\_anomaly\_interval) | Interval. | `string` | `60` | no | +| [subscription\_push\_latency\_anomaly\_message](#input\_subscription\_push\_latency\_anomaly\_message) | Custom message for the GCP Pub/Sub Subscription Push Latency Anomaly monitor | `string` | `""` | no | +| [subscription\_push\_latency\_anomaly\_seasonality](#input\_subscription\_push\_latency\_anomaly\_seasonality) | Seasonality of the algorithm | `string` | `"daily"` | no | +| [subscription\_push\_latency\_anomaly\_threshold\_critical](#input\_subscription\_push\_latency\_anomaly\_threshold\_critical) | GCP Pub/Sub Subscription Push Latency Anomaly critical threshold | `string` | `2` | no | +| [subscription\_push\_latency\_anomaly\_threshold\_warning](#input\_subscription\_push\_latency\_anomaly\_threshold\_warning) | GCP Pub/Sub Subscription Push Latency Anomaly warning threshold | `string` | `1` | no | +| [subscription\_push\_latency\_anomaly\_time\_aggregator](#input\_subscription\_push\_latency\_anomaly\_time\_aggregator) | Time aggregator for the GCP Pub/Sub Subscription Push Latency Anomaly monitor | `string` | `"avg"` | no | +| [subscription\_push\_latency\_anomaly\_timeframe](#input\_subscription\_push\_latency\_anomaly\_timeframe) | Timeframe for the GCP Pub/Sub Subscription Push Latency Anomaly monitor | `string` | `"last_10m"` | no | +| [subscription\_push\_latency\_enabled](#input\_subscription\_push\_latency\_enabled) | Flag to enable GCP Pub/Sub Subscription Push Latency High monitor | `string` | `"true"` | no | +| [subscription\_push\_latency\_extra\_tags](#input\_subscription\_push\_latency\_extra\_tags) | Extra tags for GCP Pub/Sub Subscription Push Latency High monitor | `list(string)` | `[]` | no | +| [subscription\_push\_latency\_message](#input\_subscription\_push\_latency\_message) | Custom message for the GCP Pub/Sub Subscription Push Latency High monitor | `string` | `""` | no | +| [subscription\_push\_latency\_threshold\_critical](#input\_subscription\_push\_latency\_threshold\_critical) | GCP Pub/Sub Subscription Push Latency High critical threshold | `string` | `5000` | no | +| [subscription\_push\_latency\_threshold\_warning](#input\_subscription\_push\_latency\_threshold\_warning) | GCP Pub/Sub Subscription Push Latency High warning threshold | `string` | `1000` | no | +| [subscription\_push\_latency\_time\_aggregator](#input\_subscription\_push\_latency\_time\_aggregator) | Time aggregator for the GCP Pub/Sub Subscription Push Latency High monitor | `string` | `"avg"` | no | +| [subscription\_push\_latency\_timeframe](#input\_subscription\_push\_latency\_timeframe) | Timeframe for the GCP Pub/Sub Subscription Push Latency High monitor | `string` | `"last_10m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [oldest\_unacked\_message\_age\_id](#output\_oldest\_unacked\_message\_age\_id) | id for monitor oldest\_unacked\_message\_age | +| [subscription\_push\_latency\_anomaly\_id](#output\_subscription\_push\_latency\_anomaly\_id) | id for monitor subscription\_push\_latency\_anomaly | +| [subscription\_push\_latency\_id](#output\_subscription\_push\_latency\_id) | id for monitor subscription\_push\_latency | +## Related documentation + +* [GCP Pub/Sub Metrics](https://cloud.google.com/monitoring/api/metrics_gcp#gcp-pubsub) +* [Datadog GCP Pub/Sub integration](https://docs.datadoghq.com/integrations/google_cloud_pubsub/) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/subscription/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/subscription/inputs.tf new file mode 100755 index 0000000..204a39c --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/subscription/inputs.tf @@ -0,0 +1,211 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags" { + description = "Tags used for filtering" + default = "*" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds for the new host evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# +# oldest_unacked_message_age +# + +variable "oldest_unacked_message_age_enabled" { + description = "Flag to enable GCP Pub/Sub Subscription Oldest Unacked Message Age monitor" + type = string + default = "true" +} + +variable "oldest_unacked_message_age_message" { + description = "Custom message for the GCP Pub/Sub Subscription Oldest Unacked Message Age monitor" + type = string + default = "" +} + +variable "oldest_unacked_message_age_time_aggregator" { + description = "Time aggregator for the GCP Pub/Sub Subscription Oldest Unacked Message Age monitor" + type = string + default = "min" +} + +variable "oldest_unacked_message_age_timeframe" { + description = "Timeframe for the GCP Pub/Sub Subscription Oldest Unacked Message Age monitor" + type = string + default = "last_5m" +} + +variable "oldest_unacked_message_age_threshold_warning" { + description = "GCP Pub/Sub Subscription Oldest Unacked Message Age warning threshold" + type = string + default = 30 +} + +variable "oldest_unacked_message_age_threshold_critical" { + description = "GCP Pub/Sub Subscription Oldest Unacked Message Age critical threshold" + type = string + default = 120 +} + +variable "oldest_unacked_message_age_extra_tags" { + description = "Extra tags for GCP Pub/Sub Subscription Oldest Unacked Message Age monitor" + type = list(string) + default = [] +} + +# +# subscription_push_latency +# +variable "subscription_push_latency_enabled" { + description = "Flag to enable GCP Pub/Sub Subscription Push Latency High monitor" + type = string + default = "true" +} + +variable "subscription_push_latency_message" { + description = "Custom message for the GCP Pub/Sub Subscription Push Latency High monitor" + type = string + default = "" +} + +variable "subscription_push_latency_time_aggregator" { + description = "Time aggregator for the GCP Pub/Sub Subscription Push Latency High monitor" + type = string + default = "avg" +} + +variable "subscription_push_latency_timeframe" { + description = "Timeframe for the GCP Pub/Sub Subscription Push Latency High monitor" + type = string + default = "last_10m" +} + +variable "subscription_push_latency_threshold_warning" { + description = "GCP Pub/Sub Subscription Push Latency High warning threshold" + type = string + default = 1000 +} + +variable "subscription_push_latency_threshold_critical" { + description = "GCP Pub/Sub Subscription Push Latency High critical threshold" + type = string + default = 5000 +} + +variable "subscription_push_latency_extra_tags" { + description = "Extra tags for GCP Pub/Sub Subscription Push Latency High monitor" + type = list(string) + default = [] +} + +# +# subscription_push_latency_anomaly +# +variable "subscription_push_latency_anomaly_enabled" { + description = "Flag to enable GCP Pub/Sub Subscription Push Latency Anomaly monitor" + type = string + default = "false" +} + +variable "subscription_push_latency_anomaly_message" { + description = "Custom message for the GCP Pub/Sub Subscription Push Latency Anomaly monitor" + type = string + default = "" +} + +variable "subscription_push_latency_anomaly_time_aggregator" { + description = "Time aggregator for the GCP Pub/Sub Subscription Push Latency Anomaly monitor" + type = string + default = "avg" +} + +variable "subscription_push_latency_anomaly_timeframe" { + description = "Timeframe for the GCP Pub/Sub Subscription Push Latency Anomaly monitor" + type = string + default = "last_10m" +} + +variable "subscription_push_latency_anomaly_detection_algorithm" { + description = "Anomaly Detection Algorithm used" + type = string + default = "basic" +} + +variable "subscription_push_latency_anomaly_direction" { + description = "Direction of the anomaly. It can be both, below or above." + type = string + default = "above" +} + +variable "subscription_push_latency_anomaly_alert_window" { + description = "Alert window." + type = string + default = "last_15m" +} + +variable "subscription_push_latency_anomaly_interval" { + description = "Interval." + type = string + default = 60 +} + +variable "subscription_push_latency_anomaly_count_default_zero" { + description = "Count default zero." + type = string + default = "true" +} + +variable "subscription_push_latency_anomaly_seasonality" { + description = "Seasonality of the algorithm" + type = string + default = "daily" +} + +variable "subscription_push_latency_anomaly_threshold_warning" { + description = "GCP Pub/Sub Subscription Push Latency Anomaly warning threshold" + type = string + default = 1 +} + +variable "subscription_push_latency_anomaly_threshold_critical" { + description = "GCP Pub/Sub Subscription Push Latency Anomaly critical threshold" + type = string + default = 2 +} + +variable "subscription_push_latency_anomaly_extra_tags" { + description = "Extra tags for GCP Pub/Sub Subscription Push Latency Anomaly monitor" + type = list(string) + default = [] +} + + + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/subscription/monitors-subscription.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/subscription/monitors-subscription.tf new file mode 100755 index 0000000..701852c --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/subscription/monitors-subscription.tf @@ -0,0 +1,116 @@ +###################### +# All Subscriptions # +###################### + +# +# oldest_unacked_message_age +# +resource "datadog_monitor" "oldest_unacked_message_age" { + count = var.oldest_unacked_message_age_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Pub/Sub Subscription oldest unacknowledged message {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + message = coalesce(var.oldest_unacked_message_age_message, var.message) + type = "query alert" + + query = <= ${var.oldest_unacked_message_age_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.oldest_unacked_message_age_threshold_warning + critical = var.oldest_unacked_message_age_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:pubsub", "category:subscription", "team:claranet", "created-by:terraform"], var.oldest_unacked_message_age_extra_tags) +} + +###################### +# Push Subscriptions # +###################### + +# +# subscription_push_latency +# +resource "datadog_monitor" "subscription_push_latency" { + count = var.subscription_push_latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Pub/Sub Subscription latency on push endpoint {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + message = coalesce(var.subscription_push_latency_message, var.message) + type = "query alert" + + query = <= ${var.subscription_push_latency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.subscription_push_latency_threshold_warning + critical = var.subscription_push_latency_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:pubsub", "category:subscription", "team:claranet", "created-by:terraform"], var.subscription_push_latency_extra_tags) +} + +# +# subscription_push_latency_anomaly +# +resource "datadog_monitor" "subscription_push_latency_anomaly" { + count = var.subscription_push_latency_anomaly_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Pub/Sub Subscription latency on push endpoint changed abnormally {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.subscription_push_latency_anomaly_message, var.message) + type = "query alert" + + query = <= ${var.subscription_push_latency_anomaly_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.subscription_push_latency_anomaly_threshold_warning + critical = var.subscription_push_latency_anomaly_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:pubsub", "category:subscription", "team:claranet", "created-by:terraform"], var.subscription_push_latency_anomaly_extra_tags) +} \ No newline at end of file diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/subscription/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/subscription/outputs.tf new file mode 100755 index 0000000..13883e2 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/subscription/outputs.tf @@ -0,0 +1,15 @@ +output "oldest_unacked_message_age_id" { + description = "id for monitor oldest_unacked_message_age" + value = datadog_monitor.oldest_unacked_message_age.*.id +} + +output "subscription_push_latency_id" { + description = "id for monitor subscription_push_latency" + value = datadog_monitor.subscription_push_latency.*.id +} + +output "subscription_push_latency_anomaly_id" { + description = "id for monitor subscription_push_latency_anomaly" + value = datadog_monitor.subscription_push_latency_anomaly.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/subscription/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/subscription/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/subscription/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/topic/MANIFEST.txt b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/topic/MANIFEST.txt new file mode 100755 index 0000000..6de6b50 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/topic/MANIFEST.txt @@ -0,0 +1 @@ +cloud-gcp diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/topic/README.md b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/topic/README.md new file mode 100755 index 0000000..639cb0a --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/topic/README.md @@ -0,0 +1,91 @@ +# CLOUD GCP PUBSUB TOPIC DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-cloud-gcp-pubsub-topic" { + source = "claranet/monitors/datadog//cloud/gcp/pubsub/topic" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Pub/Sub Topic ratio of sending messages with result unavailable +- Pub/Sub Topic sending messages operations +- Pub/Sub Topic sending messages with result unavailable (disabled by default) + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.sending_operations_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.unavailable_sending_operations_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.unavailable_sending_operations_ratio](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags](#input\_filter\_tags) | Tags used for filtering | `string` | `"*"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the new host evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [sending\_operations\_count\_enabled](#input\_sending\_operations\_count\_enabled) | Flag to enable GCP Pub/Sub Unavailable Sending Operations Count monitor | `string` | `"true"` | no | +| [sending\_operations\_count\_extra\_tags](#input\_sending\_operations\_count\_extra\_tags) | Extra tags for GCP Pub/Sub Sending Operations Count monitor | `list(string)` | `[]` | no | +| [sending\_operations\_count\_message](#input\_sending\_operations\_count\_message) | Custom message for the GCP Pub/Sub Sending Operations Count monitor | `string` | `""` | no | +| [sending\_operations\_count\_threshold\_critical](#input\_sending\_operations\_count\_threshold\_critical) | Critical threshold for the number of sending operations. | `string` | `0` | no | +| [sending\_operations\_count\_time\_aggregator](#input\_sending\_operations\_count\_time\_aggregator) | Timeframe for the GCP Pub/Sub Sending Operations Count monitor | `string` | `"sum"` | no | +| [sending\_operations\_count\_timeframe](#input\_sending\_operations\_count\_timeframe) | Timeframe for the GCP Pub/Sub Sending Operations Count monitor | `string` | `"last_30m"` | no | +| [unavailable\_sending\_operations\_count\_enabled](#input\_unavailable\_sending\_operations\_count\_enabled) | Flag to enable GCP Pub/Sub Unavailable Sending Operations Count monitor | `string` | `"false"` | no | +| [unavailable\_sending\_operations\_count\_extra\_tags](#input\_unavailable\_sending\_operations\_count\_extra\_tags) | Extra tags for GCP Pub/Sub Unavailable Sending Operations Count monitor | `list(string)` | `[]` | no | +| [unavailable\_sending\_operations\_count\_message](#input\_unavailable\_sending\_operations\_count\_message) | Custom message for the GCP Pub/Sub Unavailable Sending Operations Count monitor | `string` | `""` | no | +| [unavailable\_sending\_operations\_count\_threshold\_critical](#input\_unavailable\_sending\_operations\_count\_threshold\_critical) | Critical threshold for the number of unavailable sending operations | `string` | `4` | no | +| [unavailable\_sending\_operations\_count\_threshold\_warning](#input\_unavailable\_sending\_operations\_count\_threshold\_warning) | Warning threshold for the number of unavailable sending operations | `string` | `2` | no | +| [unavailable\_sending\_operations\_count\_time\_aggregator](#input\_unavailable\_sending\_operations\_count\_time\_aggregator) | Timeframe for the GCP Pub/Sub Unavailable Sending Operations Count monitor | `string` | `"sum"` | no | +| [unavailable\_sending\_operations\_count\_timeframe](#input\_unavailable\_sending\_operations\_count\_timeframe) | Timeframe for the GCP Pub/Sub Unavailable Sending Operations Count monitor | `string` | `"last_10m"` | no | +| [unavailable\_sending\_operations\_ratio\_enabled](#input\_unavailable\_sending\_operations\_ratio\_enabled) | Flag to enable GCP Pub/Sub Unavailable Sending Operations Ratio monitor | `string` | `"true"` | no | +| [unavailable\_sending\_operations\_ratio\_extra\_tags](#input\_unavailable\_sending\_operations\_ratio\_extra\_tags) | Extra tags for GCP Pub/Sub Unavailable Sending Operations Ratio monitor | `list(string)` | `[]` | no | +| [unavailable\_sending\_operations\_ratio\_message](#input\_unavailable\_sending\_operations\_ratio\_message) | Custom message for the GCP Pub/Sub Unavailable Sending Operations Ratio monitor | `string` | `""` | no | +| [unavailable\_sending\_operations\_ratio\_threshold\_critical](#input\_unavailable\_sending\_operations\_ratio\_threshold\_critical) | Critical threshold (%) for the ratio of unavailable sending operations | `string` | `20` | no | +| [unavailable\_sending\_operations\_ratio\_threshold\_warning](#input\_unavailable\_sending\_operations\_ratio\_threshold\_warning) | Warning threshold (%) for the ratio of unavailable sending operations | `string` | `10` | no | +| [unavailable\_sending\_operations\_ratio\_time\_aggregator](#input\_unavailable\_sending\_operations\_ratio\_time\_aggregator) | Timeframe for the GCP Pub/Sub Unavailable Sending Operations Ratio monitor | `string` | `"sum"` | no | +| [unavailable\_sending\_operations\_ratio\_timeframe](#input\_unavailable\_sending\_operations\_ratio\_timeframe) | Timeframe for the GCP Pub/Sub Unavailable Sending Operations Ratio monitor | `string` | `"last_10m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [sending\_operations\_count\_id](#output\_sending\_operations\_count\_id) | id for monitor sending\_operations\_count | +| [unavailable\_sending\_operations\_count\_id](#output\_unavailable\_sending\_operations\_count\_id) | id for monitor unavailable\_sending\_operations\_count | +| [unavailable\_sending\_operations\_ratio\_id](#output\_unavailable\_sending\_operations\_ratio\_id) | id for monitor unavailable\_sending\_operations\_ratio | +## Related documentation + +* [GCP Pub/Sub Metrics](https://cloud.google.com/monitoring/api/metrics_gcp#gcp-pubsub) +* [Datadog GCP Pub/Sub integration](https://docs.datadoghq.com/integrations/google_cloud_pubsub/) diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/topic/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/topic/inputs.tf new file mode 100755 index 0000000..d1b7e91 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/topic/inputs.tf @@ -0,0 +1,165 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags" { + description = "Tags used for filtering" + default = "*" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds for the new host evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# +# Sending Operations Count +# +variable "sending_operations_count_message" { + description = "Custom message for the GCP Pub/Sub Sending Operations Count monitor" + type = string + default = "" +} + +variable "sending_operations_count_time_aggregator" { + description = "Timeframe for the GCP Pub/Sub Sending Operations Count monitor" + type = string + default = "sum" +} + +variable "sending_operations_count_timeframe" { + description = "Timeframe for the GCP Pub/Sub Sending Operations Count monitor" + type = string + default = "last_30m" +} + +variable "sending_operations_count_threshold_critical" { + description = "Critical threshold for the number of sending operations." + type = string + default = 0 +} + +variable "sending_operations_count_enabled" { + description = "Flag to enable GCP Pub/Sub Unavailable Sending Operations Count monitor" + type = string + default = "true" +} + +variable "sending_operations_count_extra_tags" { + description = "Extra tags for GCP Pub/Sub Sending Operations Count monitor" + type = list(string) + default = [] +} + +# +# Unavailable Sending Operations Count +# +variable "unavailable_sending_operations_count_message" { + description = "Custom message for the GCP Pub/Sub Unavailable Sending Operations Count monitor" + type = string + default = "" +} + +variable "unavailable_sending_operations_count_time_aggregator" { + description = "Timeframe for the GCP Pub/Sub Unavailable Sending Operations Count monitor" + type = string + default = "sum" +} + +variable "unavailable_sending_operations_count_timeframe" { + description = "Timeframe for the GCP Pub/Sub Unavailable Sending Operations Count monitor" + type = string + default = "last_10m" +} + +variable "unavailable_sending_operations_count_threshold_warning" { + description = "Warning threshold for the number of unavailable sending operations" + type = string + default = 2 +} + +variable "unavailable_sending_operations_count_threshold_critical" { + description = "Critical threshold for the number of unavailable sending operations" + type = string + default = 4 +} + +variable "unavailable_sending_operations_count_enabled" { + description = "Flag to enable GCP Pub/Sub Unavailable Sending Operations Count monitor" + type = string + default = "false" +} + +variable "unavailable_sending_operations_count_extra_tags" { + description = "Extra tags for GCP Pub/Sub Unavailable Sending Operations Count monitor" + type = list(string) + default = [] +} + +# +# Unavailable Sending Operations Ratio +# +variable "unavailable_sending_operations_ratio_message" { + description = "Custom message for the GCP Pub/Sub Unavailable Sending Operations Ratio monitor" + type = string + default = "" +} + +variable "unavailable_sending_operations_ratio_time_aggregator" { + description = "Timeframe for the GCP Pub/Sub Unavailable Sending Operations Ratio monitor" + type = string + default = "sum" +} + +variable "unavailable_sending_operations_ratio_timeframe" { + description = "Timeframe for the GCP Pub/Sub Unavailable Sending Operations Ratio monitor" + type = string + default = "last_10m" +} + +variable "unavailable_sending_operations_ratio_threshold_warning" { + description = "Warning threshold (%) for the ratio of unavailable sending operations" + type = string + default = 10 +} + +variable "unavailable_sending_operations_ratio_threshold_critical" { + description = "Critical threshold (%) for the ratio of unavailable sending operations" + type = string + default = 20 +} + +variable "unavailable_sending_operations_ratio_enabled" { + description = "Flag to enable GCP Pub/Sub Unavailable Sending Operations Ratio monitor" + type = string + default = "true" +} + +variable "unavailable_sending_operations_ratio_extra_tags" { + description = "Extra tags for GCP Pub/Sub Unavailable Sending Operations Ratio monitor" + type = list(string) + default = [] +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/topic/monitors-topics.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/topic/monitors-topics.tf new file mode 100755 index 0000000..ad3ad54 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/topic/monitors-topics.tf @@ -0,0 +1,99 @@ +# +# Sending Operations Count +# +resource "datadog_monitor" "sending_operations_count" { + count = var.sending_operations_count_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Pub/Sub Topic sending messages operations {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.sending_operations_count_message, var.message) + type = "query alert" + + query = <= ${var.unavailable_sending_operations_count_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.unavailable_sending_operations_count_threshold_warning + critical = var.unavailable_sending_operations_count_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:pubsub", "category:topic", "team:claranet", "created-by:terraform"], var.unavailable_sending_operations_count_extra_tags) +} + +# +# Unavailable Sending Operations Ratio +# +resource "datadog_monitor" "unavailable_sending_operations_ratio" { + count = var.unavailable_sending_operations_ratio_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Pub/Sub Topic ratio of sending messages with result unavailable {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.unavailable_sending_operations_ratio_message, var.message) + type = "query alert" + + query = <= ${var.unavailable_sending_operations_ratio_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.unavailable_sending_operations_ratio_threshold_warning + critical = var.unavailable_sending_operations_ratio_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = false + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:cloud", "provider:gcp", "resource:pubsub", "category:topic", "team:claranet", "created-by:terraform"], var.unavailable_sending_operations_ratio_extra_tags) +} diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/topic/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/topic/outputs.tf new file mode 100755 index 0000000..4452e91 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/topic/outputs.tf @@ -0,0 +1,15 @@ +output "sending_operations_count_id" { + description = "id for monitor sending_operations_count" + value = datadog_monitor.sending_operations_count.*.id +} + +output "unavailable_sending_operations_count_id" { + description = "id for monitor unavailable_sending_operations_count" + value = datadog_monitor.unavailable_sending_operations_count.*.id +} + +output "unavailable_sending_operations_ratio_id" { + description = "id for monitor unavailable_sending_operations_ratio" + value = datadog_monitor.unavailable_sending_operations_ratio.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/topic/versions.tf b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/topic/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/cloud/gcp/pubsub/topic/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/common/alerting-message/README.md b/.terraform/modules/datadog-monitors-system-generic/common/alerting-message/README.md new file mode 100755 index 0000000..be89cfb --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/common/alerting-message/README.md @@ -0,0 +1,58 @@ +# ALERTING MESSAGE Datadog Generator + +## How to use this module + +``` +module "datadog-message-alerting" { + source = "git::ssh://git@bitbucket.org/morea/terraform.feature.datadog.git//common/alerting-message?ref={revision}" + + message_alert = "${var.oncall_24x7}" + message_warning = "${var.oncall_business_hours}" + message_nodata = "${var.oncall_nodata}" +} +``` + +## Purpose + +Creates a DataDog monitor alert message with the following inputs : + +* A broadcast channel for critical alerts +* A broadcast channel for nodata alerts +* A broadcast channel for warning alerts +* Prepend text free string +* Append text free string + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|:----:|:-----:|:-----:| +| append_text | Optional free text string to append to alert | string | `` | no | +| message_alert | Define a broadcast channel for critical alerts | string | - | yes | +| message_nodata | Define a broadcast channel for nodata alerts | string | `` | no | +| message_warning | Define a broadcast channel for warning alerts | string | - | no | +| prepend_text | Optional free text string to prepend to alert | string | `` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| alerting-message | The generated message string | + +## Related documentation + +Datadog notifications official documentation: [https://docs.datadoghq.com/monitors/notifications/?tab=is_alertis_warning](https://docs.datadoghq.com/monitors/notifications/?tab=is_alertis_warning) + +## Notes + +This module aims to generate a valid message to split notification into different destinations based on its type (alert, warning, no data). + +If this way matchs your need so you should be able to use its output alone directly for your monitors. +You can even use `append_text` and `prepend_text` variables to add context or documentation to monitors. + +Else you can still use its output with one or multiple destinations to use it in your own messsage (i.e. with `{{#is_match}}` splitting mechanism). + +Here is some tips to understand the behavior of this module and espacially its resulted output: +* Only `message_alert` is mandatory +* If `message_warning` or `message_nodata` are not defined it will use `message_alert` by default +* You can "disable" one notification type by set its variable to empty (i.e. `message_warning = ""`) +* feel free to use this module multiple times with different combinations to suit your needs diff --git a/.terraform/modules/datadog-monitors-system-generic/common/alerting-message/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/common/alerting-message/inputs.tf new file mode 100755 index 0000000..60c1305 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/common/alerting-message/inputs.tf @@ -0,0 +1,30 @@ +variable "message_alert" { + description = "Define a broadcast channel for critical alerts" + type = string +} + +variable "message_warning" { + description = "Define a broadcast channel for warning alerts" + type = string + default = null +} + +variable "message_nodata" { + description = "Define a broadcast channel for nodata alerts" + type = string + default = null +} + +variable "prepend_text" { + description = "Optional free text string to prepend to alert" + type = string + default = "" +} + +variable "append_text" { + description = "Optional free text string to append to alert" + type = string + default = "" +} + + diff --git a/.terraform/modules/datadog-monitors-system-generic/common/alerting-message/main.tf b/.terraform/modules/datadog-monitors-system-generic/common/alerting-message/main.tf new file mode 100755 index 0000000..9efb7b7 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/common/alerting-message/main.tf @@ -0,0 +1,19 @@ +data "template_file" "alerting-message" { + template = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cluster_initializing_shards](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.cluster_relocating_shards](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.cluster_status_not_green](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.cluster_unassigned_shards](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.fetch_change](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.fetch_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.field_data_evictions_change](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.flush_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.http_connections_anomaly](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.indexing_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.jvm_gc_old_collection_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.jvm_gc_young_collection_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.jvm_heap_memory_usage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.jvm_memory_old_usage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.jvm_memory_young_usage](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.node_free_space](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.not_responding](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.query_cache_evictions_change](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.request_cache_evictions_change](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.search_query_change](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.search_query_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.task_time_in_queue_change](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cluster\_initializing\_shards\_enabled](#input\_cluster\_initializing\_shards\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [cluster\_initializing\_shards\_extra\_tags](#input\_cluster\_initializing\_shards\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [cluster\_initializing\_shards\_message](#input\_cluster\_initializing\_shards\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [cluster\_initializing\_shards\_threshold\_critical](#input\_cluster\_initializing\_shards\_threshold\_critical) | Cluster Status critical threshold | `string` | `2` | no | +| [cluster\_initializing\_shards\_threshold\_warning](#input\_cluster\_initializing\_shards\_threshold\_warning) | Cluster Status warning threshold | `string` | `1` | no | +| [cluster\_initializing\_shards\_time\_aggregator](#input\_cluster\_initializing\_shards\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [cluster\_initializing\_shards\_timeframe](#input\_cluster\_initializing\_shards\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_5m"` | no | +| [cluster\_relocating\_shards\_enabled](#input\_cluster\_relocating\_shards\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [cluster\_relocating\_shards\_extra\_tags](#input\_cluster\_relocating\_shards\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [cluster\_relocating\_shards\_message](#input\_cluster\_relocating\_shards\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [cluster\_relocating\_shards\_threshold\_critical](#input\_cluster\_relocating\_shards\_threshold\_critical) | Cluster Status critical threshold | `string` | `2` | no | +| [cluster\_relocating\_shards\_threshold\_warning](#input\_cluster\_relocating\_shards\_threshold\_warning) | Cluster Status warning threshold | `string` | `1` | no | +| [cluster\_relocating\_shards\_time\_aggregator](#input\_cluster\_relocating\_shards\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [cluster\_relocating\_shards\_timeframe](#input\_cluster\_relocating\_shards\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_5m"` | no | +| [cluster\_status\_not\_green\_enabled](#input\_cluster\_status\_not\_green\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [cluster\_status\_not\_green\_extra\_tags](#input\_cluster\_status\_not\_green\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [cluster\_status\_not\_green\_message](#input\_cluster\_status\_not\_green\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [cluster\_status\_not\_green\_threshold\_critical](#input\_cluster\_status\_not\_green\_threshold\_critical) | Cluster Status critical threshold | `string` | `0` | no | +| [cluster\_status\_not\_green\_threshold\_warning](#input\_cluster\_status\_not\_green\_threshold\_warning) | Cluster Status warning threshold | `string` | `1` | no | +| [cluster\_status\_not\_green\_time\_aggregator](#input\_cluster\_status\_not\_green\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [cluster\_status\_not\_green\_timeframe](#input\_cluster\_status\_not\_green\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_5m"` | no | +| [cluster\_unassigned\_shards\_enabled](#input\_cluster\_unassigned\_shards\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [cluster\_unassigned\_shards\_extra\_tags](#input\_cluster\_unassigned\_shards\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [cluster\_unassigned\_shards\_message](#input\_cluster\_unassigned\_shards\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [cluster\_unassigned\_shards\_threshold\_critical](#input\_cluster\_unassigned\_shards\_threshold\_critical) | Cluster Status critical threshold | `string` | `2` | no | +| [cluster\_unassigned\_shards\_threshold\_warning](#input\_cluster\_unassigned\_shards\_threshold\_warning) | Cluster Status warning threshold | `string` | `1` | no | +| [cluster\_unassigned\_shards\_time\_aggregator](#input\_cluster\_unassigned\_shards\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [cluster\_unassigned\_shards\_timeframe](#input\_cluster\_unassigned\_shards\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [fetch\_change\_enabled](#input\_fetch\_change\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [fetch\_change\_extra\_tags](#input\_fetch\_change\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [fetch\_change\_message](#input\_fetch\_change\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [fetch\_change\_threshold\_critical](#input\_fetch\_change\_threshold\_critical) | Cluster Status critical threshold | `string` | `100` | no | +| [fetch\_change\_threshold\_warning](#input\_fetch\_change\_threshold\_warning) | Cluster Status warning threshold | `string` | `75` | no | +| [fetch\_change\_time\_aggregator](#input\_fetch\_change\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [fetch\_change\_timeframe](#input\_fetch\_change\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_10m"` | no | +| [fetch\_change\_timeshift](#input\_fetch\_change\_timeshift) | Timeshift for the Cluster Status monitor | `string` | `"last_10m"` | no | +| [fetch\_latency\_enabled](#input\_fetch\_latency\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [fetch\_latency\_extra\_tags](#input\_fetch\_latency\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [fetch\_latency\_message](#input\_fetch\_latency\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [fetch\_latency\_threshold\_critical](#input\_fetch\_latency\_threshold\_critical) | Cluster Status critical threshold | `string` | `20` | no | +| [fetch\_latency\_threshold\_warning](#input\_fetch\_latency\_threshold\_warning) | Cluster Status warning threshold | `string` | `10` | no | +| [fetch\_latency\_time\_aggregator](#input\_fetch\_latency\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"min"` | no | +| [fetch\_latency\_timeframe](#input\_fetch\_latency\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_15m"` | no | +| [field\_data\_evictions\_change\_enabled](#input\_field\_data\_evictions\_change\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [field\_data\_evictions\_change\_extra\_tags](#input\_field\_data\_evictions\_change\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [field\_data\_evictions\_change\_message](#input\_field\_data\_evictions\_change\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [field\_data\_evictions\_change\_threshold\_critical](#input\_field\_data\_evictions\_change\_threshold\_critical) | Cluster Status critical threshold | `string` | `120` | no | +| [field\_data\_evictions\_change\_threshold\_warning](#input\_field\_data\_evictions\_change\_threshold\_warning) | Cluster Status warning threshold | `string` | `60` | no | +| [field\_data\_evictions\_change\_time\_aggregator](#input\_field\_data\_evictions\_change\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [field\_data\_evictions\_change\_timeframe](#input\_field\_data\_evictions\_change\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_15m"` | no | +| [field\_data\_evictions\_change\_timeshift](#input\_field\_data\_evictions\_change\_timeshift) | Timeframe for the Cluster Status monitor | `string` | `"last_15m"` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [flush\_latency\_enabled](#input\_flush\_latency\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [flush\_latency\_extra\_tags](#input\_flush\_latency\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [flush\_latency\_message](#input\_flush\_latency\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [flush\_latency\_threshold\_critical](#input\_flush\_latency\_threshold\_critical) | Cluster Status critical threshold | `string` | `150` | no | +| [flush\_latency\_threshold\_warning](#input\_flush\_latency\_threshold\_warning) | Cluster Status warning threshold | `string` | `100` | no | +| [flush\_latency\_time\_aggregator](#input\_flush\_latency\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [flush\_latency\_timeframe](#input\_flush\_latency\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_15m"` | no | +| [http\_connections\_anomaly\_alert\_window](#input\_http\_connections\_anomaly\_alert\_window) | Alert window. | `string` | `"last_15m"` | no | +| [http\_connections\_anomaly\_count\_default\_zero](#input\_http\_connections\_anomaly\_count\_default\_zero) | Count default zero. | `string` | `"true"` | no | +| [http\_connections\_anomaly\_detection\_algorithm](#input\_http\_connections\_anomaly\_detection\_algorithm) | Anomaly Detection Algorithm used | `string` | `"agile"` | no | +| [http\_connections\_anomaly\_deviations](#input\_http\_connections\_anomaly\_deviations) | Deviations to detect the anomaly | `string` | `2` | no | +| [http\_connections\_anomaly\_direction](#input\_http\_connections\_anomaly\_direction) | Direction of the anomaly. It can be both, below or above. | `string` | `"above"` | no | +| [http\_connections\_anomaly\_enabled](#input\_http\_connections\_anomaly\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [http\_connections\_anomaly\_extra\_tags](#input\_http\_connections\_anomaly\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [http\_connections\_anomaly\_interval](#input\_http\_connections\_anomaly\_interval) | Interval. | `string` | `60` | no | +| [http\_connections\_anomaly\_message](#input\_http\_connections\_anomaly\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [http\_connections\_anomaly\_seasonality](#input\_http\_connections\_anomaly\_seasonality) | Seasonality of the algorithm | `string` | `"hourly"` | no | +| [http\_connections\_anomaly\_threshold\_critical](#input\_http\_connections\_anomaly\_threshold\_critical) | Cluster Status critical threshold | `string` | `1` | no | +| [http\_connections\_anomaly\_threshold\_warning](#input\_http\_connections\_anomaly\_threshold\_warning) | Cluster Status warning threshold | `string` | `0.75` | no | +| [http\_connections\_anomaly\_time\_aggregator](#input\_http\_connections\_anomaly\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [http\_connections\_anomaly\_timeframe](#input\_http\_connections\_anomaly\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_4h"` | no | +| [indexing\_latency\_enabled](#input\_indexing\_latency\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [indexing\_latency\_extra\_tags](#input\_indexing\_latency\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [indexing\_latency\_message](#input\_indexing\_latency\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [indexing\_latency\_threshold\_critical](#input\_indexing\_latency\_threshold\_critical) | Cluster Status critical threshold | `string` | `30` | no | +| [indexing\_latency\_threshold\_warning](#input\_indexing\_latency\_threshold\_warning) | Cluster Status warning threshold | `string` | `15` | no | +| [indexing\_latency\_time\_aggregator](#input\_indexing\_latency\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [indexing\_latency\_timeframe](#input\_indexing\_latency\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_10m"` | no | +| [jvm\_gc\_old\_collection\_latency\_enabled](#input\_jvm\_gc\_old\_collection\_latency\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [jvm\_gc\_old\_collection\_latency\_extra\_tags](#input\_jvm\_gc\_old\_collection\_latency\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [jvm\_gc\_old\_collection\_latency\_message](#input\_jvm\_gc\_old\_collection\_latency\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [jvm\_gc\_old\_collection\_latency\_threshold\_critical](#input\_jvm\_gc\_old\_collection\_latency\_threshold\_critical) | Cluster Status critical threshold | `string` | `300` | no | +| [jvm\_gc\_old\_collection\_latency\_threshold\_warning](#input\_jvm\_gc\_old\_collection\_latency\_threshold\_warning) | Cluster Status warning threshold | `string` | `200` | no | +| [jvm\_gc\_old\_collection\_latency\_time\_aggregator](#input\_jvm\_gc\_old\_collection\_latency\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [jvm\_gc\_old\_collection\_latency\_timeframe](#input\_jvm\_gc\_old\_collection\_latency\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_15m"` | no | +| [jvm\_gc\_young\_collection\_latency\_enabled](#input\_jvm\_gc\_young\_collection\_latency\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [jvm\_gc\_young\_collection\_latency\_extra\_tags](#input\_jvm\_gc\_young\_collection\_latency\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [jvm\_gc\_young\_collection\_latency\_message](#input\_jvm\_gc\_young\_collection\_latency\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [jvm\_gc\_young\_collection\_latency\_threshold\_critical](#input\_jvm\_gc\_young\_collection\_latency\_threshold\_critical) | Cluster Status critical threshold | `string` | `40` | no | +| [jvm\_gc\_young\_collection\_latency\_threshold\_warning](#input\_jvm\_gc\_young\_collection\_latency\_threshold\_warning) | Cluster Status warning threshold | `string` | `20` | no | +| [jvm\_gc\_young\_collection\_latency\_time\_aggregator](#input\_jvm\_gc\_young\_collection\_latency\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [jvm\_gc\_young\_collection\_latency\_timeframe](#input\_jvm\_gc\_young\_collection\_latency\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_15m"` | no | +| [jvm\_heap\_memory\_usage\_enabled](#input\_jvm\_heap\_memory\_usage\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [jvm\_heap\_memory\_usage\_extra\_tags](#input\_jvm\_heap\_memory\_usage\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [jvm\_heap\_memory\_usage\_message](#input\_jvm\_heap\_memory\_usage\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [jvm\_heap\_memory\_usage\_threshold\_critical](#input\_jvm\_heap\_memory\_usage\_threshold\_critical) | Cluster Status critical threshold | `string` | `90` | no | +| [jvm\_heap\_memory\_usage\_threshold\_warning](#input\_jvm\_heap\_memory\_usage\_threshold\_warning) | Cluster Status warning threshold | `string` | `80` | no | +| [jvm\_heap\_memory\_usage\_time\_aggregator](#input\_jvm\_heap\_memory\_usage\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [jvm\_heap\_memory\_usage\_timeframe](#input\_jvm\_heap\_memory\_usage\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_5m"` | no | +| [jvm\_memory\_old\_usage\_enabled](#input\_jvm\_memory\_old\_usage\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [jvm\_memory\_old\_usage\_extra\_tags](#input\_jvm\_memory\_old\_usage\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [jvm\_memory\_old\_usage\_message](#input\_jvm\_memory\_old\_usage\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [jvm\_memory\_old\_usage\_threshold\_critical](#input\_jvm\_memory\_old\_usage\_threshold\_critical) | Cluster Status critical threshold | `string` | `90` | no | +| [jvm\_memory\_old\_usage\_threshold\_warning](#input\_jvm\_memory\_old\_usage\_threshold\_warning) | Cluster Status warning threshold | `string` | `80` | no | +| [jvm\_memory\_old\_usage\_time\_aggregator](#input\_jvm\_memory\_old\_usage\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [jvm\_memory\_old\_usage\_timeframe](#input\_jvm\_memory\_old\_usage\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_10m"` | no | +| [jvm\_memory\_young\_usage\_enabled](#input\_jvm\_memory\_young\_usage\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [jvm\_memory\_young\_usage\_extra\_tags](#input\_jvm\_memory\_young\_usage\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [jvm\_memory\_young\_usage\_message](#input\_jvm\_memory\_young\_usage\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [jvm\_memory\_young\_usage\_threshold\_critical](#input\_jvm\_memory\_young\_usage\_threshold\_critical) | Cluster Status critical threshold | `string` | `90` | no | +| [jvm\_memory\_young\_usage\_threshold\_warning](#input\_jvm\_memory\_young\_usage\_threshold\_warning) | Cluster Status warning threshold | `string` | `80` | no | +| [jvm\_memory\_young\_usage\_time\_aggregator](#input\_jvm\_memory\_young\_usage\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [jvm\_memory\_young\_usage\_timeframe](#input\_jvm\_memory\_young\_usage\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_10m"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before begin to monitor new host | `number` | `300` | no | +| [node\_free\_space\_enabled](#input\_node\_free\_space\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [node\_free\_space\_extra\_tags](#input\_node\_free\_space\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [node\_free\_space\_message](#input\_node\_free\_space\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [node\_free\_space\_threshold\_critical](#input\_node\_free\_space\_threshold\_critical) | Cluster Status critical threshold | `string` | `10` | no | +| [node\_free\_space\_threshold\_warning](#input\_node\_free\_space\_threshold\_warning) | Cluster Status warning threshold | `string` | `20` | no | +| [node\_free\_space\_time\_aggregator](#input\_node\_free\_space\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"sum"` | no | +| [node\_free\_space\_timeframe](#input\_node\_free\_space\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_5m"` | no | +| [not\_responding\_enabled](#input\_not\_responding\_enabled) | Flag to enable Elasticsearch does not respond monitor | `string` | `"true"` | no | +| [not\_responding\_extra\_tags](#input\_not\_responding\_extra\_tags) | Extra tags for Elasticsearch does not respond monitor | `list(string)` | `[]` | no | +| [not\_responding\_message](#input\_not\_responding\_message) | Custom message for Elasticsearch does not respond monitor | `string` | `""` | no | +| [not\_responding\_no\_data\_timeframe](#input\_not\_responding\_no\_data\_timeframe) | Elasticsearch not responding monitor no data timeframe | `string` | `10` | no | +| [not\_responding\_threshold\_warning](#input\_not\_responding\_threshold\_warning) | Elasticsearch not responding limit (warning threshold) | `number` | `3` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [query\_cache\_evictions\_change\_enabled](#input\_query\_cache\_evictions\_change\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [query\_cache\_evictions\_change\_extra\_tags](#input\_query\_cache\_evictions\_change\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [query\_cache\_evictions\_change\_message](#input\_query\_cache\_evictions\_change\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [query\_cache\_evictions\_change\_threshold\_critical](#input\_query\_cache\_evictions\_change\_threshold\_critical) | Cluster Status critical threshold | `string` | `120` | no | +| [query\_cache\_evictions\_change\_threshold\_warning](#input\_query\_cache\_evictions\_change\_threshold\_warning) | Cluster Status warning threshold | `string` | `60` | no | +| [query\_cache\_evictions\_change\_time\_aggregator](#input\_query\_cache\_evictions\_change\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [query\_cache\_evictions\_change\_timeframe](#input\_query\_cache\_evictions\_change\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_15m"` | no | +| [query\_cache\_evictions\_change\_timeshift](#input\_query\_cache\_evictions\_change\_timeshift) | Timeframe for the Cluster Status monitor | `string` | `"last_15m"` | no | +| [request\_cache\_evictions\_change\_enabled](#input\_request\_cache\_evictions\_change\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [request\_cache\_evictions\_change\_extra\_tags](#input\_request\_cache\_evictions\_change\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [request\_cache\_evictions\_change\_message](#input\_request\_cache\_evictions\_change\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [request\_cache\_evictions\_change\_threshold\_critical](#input\_request\_cache\_evictions\_change\_threshold\_critical) | Cluster Status critical threshold | `string` | `120` | no | +| [request\_cache\_evictions\_change\_threshold\_warning](#input\_request\_cache\_evictions\_change\_threshold\_warning) | Cluster Status warning threshold | `string` | `60` | no | +| [request\_cache\_evictions\_change\_time\_aggregator](#input\_request\_cache\_evictions\_change\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [request\_cache\_evictions\_change\_timeframe](#input\_request\_cache\_evictions\_change\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_15m"` | no | +| [request\_cache\_evictions\_change\_timeshift](#input\_request\_cache\_evictions\_change\_timeshift) | Timeshift for the Cluster Status monitor | `string` | `"last_15m"` | no | +| [search\_query\_change\_enabled](#input\_search\_query\_change\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [search\_query\_change\_extra\_tags](#input\_search\_query\_change\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [search\_query\_change\_message](#input\_search\_query\_change\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [search\_query\_change\_threshold\_critical](#input\_search\_query\_change\_threshold\_critical) | Cluster Status critical threshold | `string` | `100` | no | +| [search\_query\_change\_threshold\_warning](#input\_search\_query\_change\_threshold\_warning) | Cluster Status warning threshold | `string` | `75` | no | +| [search\_query\_change\_time\_aggregator](#input\_search\_query\_change\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [search\_query\_change\_timeframe](#input\_search\_query\_change\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_10m"` | no | +| [search\_query\_change\_timeshift](#input\_search\_query\_change\_timeshift) | Timeshift for the Cluster Status monitor | `string` | `"last_10m"` | no | +| [search\_query\_latency\_enabled](#input\_search\_query\_latency\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [search\_query\_latency\_extra\_tags](#input\_search\_query\_latency\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [search\_query\_latency\_message](#input\_search\_query\_latency\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [search\_query\_latency\_threshold\_critical](#input\_search\_query\_latency\_threshold\_critical) | Cluster Status critical threshold | `string` | `20` | no | +| [search\_query\_latency\_threshold\_warning](#input\_search\_query\_latency\_threshold\_warning) | Cluster Status warning threshold | `string` | `10` | no | +| [search\_query\_latency\_time\_aggregator](#input\_search\_query\_latency\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [search\_query\_latency\_timeframe](#input\_search\_query\_latency\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_15m"` | no | +| [task\_time\_in\_queue\_change\_enabled](#input\_task\_time\_in\_queue\_change\_enabled) | Flag to enable Cluster Status monitor | `string` | `"true"` | no | +| [task\_time\_in\_queue\_change\_extra\_tags](#input\_task\_time\_in\_queue\_change\_extra\_tags) | Extra tags for Cluster Status monitor | `list(string)` | `[]` | no | +| [task\_time\_in\_queue\_change\_message](#input\_task\_time\_in\_queue\_change\_message) | Custom message for the Cluster Status monitor | `string` | `""` | no | +| [task\_time\_in\_queue\_change\_threshold\_critical](#input\_task\_time\_in\_queue\_change\_threshold\_critical) | Cluster Status critical threshold | `string` | `200` | no | +| [task\_time\_in\_queue\_change\_threshold\_warning](#input\_task\_time\_in\_queue\_change\_threshold\_warning) | Cluster Status warning threshold | `string` | `100` | no | +| [task\_time\_in\_queue\_change\_time\_aggregator](#input\_task\_time\_in\_queue\_change\_time\_aggregator) | Time aggregator for the Cluster Status monitor | `string` | `"avg"` | no | +| [task\_time\_in\_queue\_change\_timeframe](#input\_task\_time\_in\_queue\_change\_timeframe) | Timeframe for the Cluster Status monitor | `string` | `"last_10m"` | no | +| [task\_time\_in\_queue\_change\_timeshift](#input\_task\_time\_in\_queue\_change\_timeshift) | Timeshift for the Cluster Status monitor | `string` | `"last_10m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cluster\_initializing\_shards\_id](#output\_cluster\_initializing\_shards\_id) | id for monitor cluster\_initializing\_shards | +| [cluster\_relocating\_shards\_id](#output\_cluster\_relocating\_shards\_id) | id for monitor cluster\_relocating\_shards | +| [cluster\_status\_not\_green\_id](#output\_cluster\_status\_not\_green\_id) | id for monitor cluster\_status\_not\_green | +| [cluster\_unassigned\_shards\_id](#output\_cluster\_unassigned\_shards\_id) | id for monitor cluster\_unassigned\_shards | +| [fetch\_change\_id](#output\_fetch\_change\_id) | id for monitor fetch\_change | +| [fetch\_latency\_id](#output\_fetch\_latency\_id) | id for monitor fetch\_latency | +| [field\_data\_evictions\_change\_id](#output\_field\_data\_evictions\_change\_id) | id for monitor field\_data\_evictions\_change | +| [flush\_latency\_id](#output\_flush\_latency\_id) | id for monitor flush\_latency | +| [http\_connections\_anomaly\_id](#output\_http\_connections\_anomaly\_id) | id for monitor http\_connections\_anomaly | +| [indexing\_latency\_id](#output\_indexing\_latency\_id) | id for monitor indexing\_latency | +| [jvm\_gc\_old\_collection\_latency\_id](#output\_jvm\_gc\_old\_collection\_latency\_id) | id for monitor jvm\_gc\_old\_collection\_latency | +| [jvm\_gc\_young\_collection\_latency\_id](#output\_jvm\_gc\_young\_collection\_latency\_id) | id for monitor jvm\_gc\_young\_collection\_latency | +| [jvm\_heap\_memory\_usage\_id](#output\_jvm\_heap\_memory\_usage\_id) | id for monitor jvm\_heap\_memory\_usage | +| [jvm\_memory\_old\_usage\_id](#output\_jvm\_memory\_old\_usage\_id) | id for monitor jvm\_memory\_old\_usage | +| [jvm\_memory\_young\_usage\_id](#output\_jvm\_memory\_young\_usage\_id) | id for monitor jvm\_memory\_young\_usage | +| [node\_free\_space\_id](#output\_node\_free\_space\_id) | id for monitor node\_free\_space | +| [not\_responding\_id](#output\_not\_responding\_id) | id for monitor not\_responding | +| [query\_cache\_evictions\_change\_id](#output\_query\_cache\_evictions\_change\_id) | id for monitor query\_cache\_evictions\_change | +| [request\_cache\_evictions\_change\_id](#output\_request\_cache\_evictions\_change\_id) | id for monitor request\_cache\_evictions\_change | +| [search\_query\_change\_id](#output\_search\_query\_change\_id) | id for monitor search\_query\_change | +| [search\_query\_latency\_id](#output\_search\_query\_latency\_id) | id for monitor search\_query\_latency | +| [task\_time\_in\_queue\_change\_id](#output\_task\_time\_in\_queue\_change\_id) | id for monitor task\_time\_in\_queue\_change | +## Related documentation +* [Integration Datadog & ElasticSearch](https://docs.datadoghq.com/integrations/elastic/) +* [How to monitor ElasticSearch with Datadog](https://www.datadoghq.com/blog/monitor-elasticsearch-datadog/) diff --git a/.terraform/modules/datadog-monitors-system-generic/database/elasticsearch/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/database/elasticsearch/inputs.tf new file mode 100755 index 0000000..dc19e6f --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/elasticsearch/inputs.tf @@ -0,0 +1,1103 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before begin to monitor new host" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +# +# Cluster Status Not Green +# +variable "cluster_status_not_green_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "cluster_status_not_green_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "cluster_status_not_green_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_5m" +} + +variable "cluster_status_not_green_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 1 +} + +variable "cluster_status_not_green_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 0 +} + +variable "cluster_status_not_green_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "cluster_status_not_green_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Cluster Initializing Shards +# +variable "cluster_initializing_shards_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "cluster_initializing_shards_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "cluster_initializing_shards_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_5m" +} + +variable "cluster_initializing_shards_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 1 +} + +variable "cluster_initializing_shards_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 2 +} + +variable "cluster_initializing_shards_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "cluster_initializing_shards_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Cluster Relocating Shards +# +variable "cluster_relocating_shards_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "cluster_relocating_shards_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "cluster_relocating_shards_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_5m" +} + +variable "cluster_relocating_shards_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 1 +} + +variable "cluster_relocating_shards_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 2 +} + +variable "cluster_relocating_shards_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "cluster_relocating_shards_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Cluster Unassigned Shards +# +variable "cluster_unassigned_shards_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "cluster_unassigned_shards_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "cluster_unassigned_shards_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_5m" +} + +variable "cluster_unassigned_shards_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 1 +} + +variable "cluster_unassigned_shards_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 2 +} + +variable "cluster_unassigned_shards_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "cluster_unassigned_shards_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Free Space in nodes +# +variable "node_free_space_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "node_free_space_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "sum" +} + +variable "node_free_space_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_5m" +} + +variable "node_free_space_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 20 +} + +variable "node_free_space_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 10 +} + +variable "node_free_space_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "node_free_space_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# JVM Heap Memory Usage +# +variable "jvm_heap_memory_usage_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "jvm_heap_memory_usage_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "jvm_heap_memory_usage_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_5m" +} + +variable "jvm_heap_memory_usage_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 80 +} + +variable "jvm_heap_memory_usage_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 90 +} + +variable "jvm_heap_memory_usage_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "jvm_heap_memory_usage_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# JVM Memory Young Usage +# +variable "jvm_memory_young_usage_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "jvm_memory_young_usage_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "jvm_memory_young_usage_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_10m" +} + +variable "jvm_memory_young_usage_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 80 +} + +variable "jvm_memory_young_usage_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 90 +} + +variable "jvm_memory_young_usage_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "jvm_memory_young_usage_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# JVM Memory Old Usage +# +variable "jvm_memory_old_usage_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "jvm_memory_old_usage_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "jvm_memory_old_usage_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_10m" +} + +variable "jvm_memory_old_usage_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 80 +} + +variable "jvm_memory_old_usage_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 90 +} + +variable "jvm_memory_old_usage_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "jvm_memory_old_usage_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# JVM Garbace Collector Old Collection Latency +# +variable "jvm_gc_old_collection_latency_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "jvm_gc_old_collection_latency_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "jvm_gc_old_collection_latency_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_15m" +} + +variable "jvm_gc_old_collection_latency_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 200 +} + +variable "jvm_gc_old_collection_latency_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 300 +} + +variable "jvm_gc_old_collection_latency_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "jvm_gc_old_collection_latency_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# JVM Garbace Collector Young Collection Latency +# +variable "jvm_gc_young_collection_latency_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "jvm_gc_young_collection_latency_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "jvm_gc_young_collection_latency_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_15m" +} + +variable "jvm_gc_young_collection_latency_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 20 +} + +variable "jvm_gc_young_collection_latency_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 40 +} + +variable "jvm_gc_young_collection_latency_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "jvm_gc_young_collection_latency_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Indexing Latency +# +variable "indexing_latency_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "indexing_latency_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "indexing_latency_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_10m" +} + +variable "indexing_latency_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 15 +} + +variable "indexing_latency_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 30 +} + +variable "indexing_latency_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "indexing_latency_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Flush Latency +# +variable "flush_latency_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "flush_latency_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "flush_latency_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_15m" +} + +variable "flush_latency_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 100 +} + +variable "flush_latency_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 150 +} + +variable "flush_latency_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "flush_latency_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Open HTTP Connections Anomaly +# +variable "http_connections_anomaly_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "http_connections_anomaly_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "http_connections_anomaly_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_4h" +} + +variable "http_connections_anomaly_detection_algorithm" { + description = "Anomaly Detection Algorithm used" + type = string + default = "agile" +} + +variable "http_connections_anomaly_deviations" { + description = "Deviations to detect the anomaly" + type = string + default = 2 +} + +variable "http_connections_anomaly_direction" { + description = "Direction of the anomaly. It can be both, below or above." + type = string + default = "above" +} + +variable "http_connections_anomaly_alert_window" { + description = "Alert window." + type = string + default = "last_15m" +} + +variable "http_connections_anomaly_interval" { + description = "Interval." + type = string + default = 60 +} + +variable "http_connections_anomaly_count_default_zero" { + description = "Count default zero." + type = string + default = "true" +} + +variable "http_connections_anomaly_seasonality" { + description = "Seasonality of the algorithm" + type = string + default = "hourly" +} + +variable "http_connections_anomaly_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 0.75 +} + +variable "http_connections_anomaly_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 1 +} + +variable "http_connections_anomaly_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "http_connections_anomaly_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Query Latency +# +variable "search_query_latency_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "search_query_latency_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "search_query_latency_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_15m" +} + +variable "search_query_latency_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 10 +} + +variable "search_query_latency_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 20 +} + +variable "search_query_latency_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "search_query_latency_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Fetch Latency +# +variable "fetch_latency_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "fetch_latency_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "min" +} + +variable "fetch_latency_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_15m" +} + +variable "fetch_latency_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 10 +} + +variable "fetch_latency_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 20 +} + +variable "fetch_latency_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "fetch_latency_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Search Query Change +# +variable "search_query_change_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "search_query_change_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "search_query_change_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_10m" +} + +variable "search_query_change_timeshift" { + description = "Timeshift for the Cluster Status monitor" + type = string + default = "last_10m" +} + +variable "search_query_change_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 75 +} + +variable "search_query_change_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 100 +} + +variable "search_query_change_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "search_query_change_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Fetch Change +# +variable "fetch_change_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "fetch_change_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "fetch_change_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_10m" +} + +variable "fetch_change_timeshift" { + description = "Timeshift for the Cluster Status monitor" + type = string + default = "last_10m" +} + +variable "fetch_change_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 75 +} + +variable "fetch_change_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 100 +} + +variable "fetch_change_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "fetch_change_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Field Data Evictions +# +variable "field_data_evictions_change_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "field_data_evictions_change_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "field_data_evictions_change_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_15m" +} + +variable "field_data_evictions_change_timeshift" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_15m" +} + +variable "field_data_evictions_change_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 60 +} + +variable "field_data_evictions_change_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 120 +} + +variable "field_data_evictions_change_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "field_data_evictions_change_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Query Cache Evictions +# +variable "query_cache_evictions_change_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "query_cache_evictions_change_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "query_cache_evictions_change_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_15m" +} + +variable "query_cache_evictions_change_timeshift" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_15m" +} + +variable "query_cache_evictions_change_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 60 +} + +variable "query_cache_evictions_change_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 120 +} + +variable "query_cache_evictions_change_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "query_cache_evictions_change_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Request Cache Evictions +# +variable "request_cache_evictions_change_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "request_cache_evictions_change_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "request_cache_evictions_change_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_15m" +} + +variable "request_cache_evictions_change_timeshift" { + description = "Timeshift for the Cluster Status monitor" + type = string + default = "last_15m" +} + +variable "request_cache_evictions_change_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 60 +} + +variable "request_cache_evictions_change_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 120 +} + +variable "request_cache_evictions_change_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "request_cache_evictions_change_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Task Time in Queue +# +variable "task_time_in_queue_change_message" { + description = "Custom message for the Cluster Status monitor" + type = string + default = "" +} + +variable "task_time_in_queue_change_time_aggregator" { + description = "Time aggregator for the Cluster Status monitor" + type = string + default = "avg" +} + +variable "task_time_in_queue_change_timeframe" { + description = "Timeframe for the Cluster Status monitor" + type = string + default = "last_10m" +} + +variable "task_time_in_queue_change_timeshift" { + description = "Timeshift for the Cluster Status monitor" + type = string + default = "last_10m" +} + +variable "task_time_in_queue_change_threshold_warning" { + description = "Cluster Status warning threshold" + type = string + default = 100 +} + +variable "task_time_in_queue_change_threshold_critical" { + description = "Cluster Status critical threshold" + type = string + default = 200 +} + +variable "task_time_in_queue_change_enabled" { + description = "Flag to enable Cluster Status monitor" + type = string + default = "true" +} + +variable "task_time_in_queue_change_extra_tags" { + description = "Extra tags for Cluster Status monitor" + type = list(string) + default = [] +} + +# +# Service Check +# + +variable "not_responding_enabled" { + description = "Flag to enable Elasticsearch does not respond monitor" + type = string + default = "true" +} + +variable "not_responding_message" { + description = "Custom message for Elasticsearch does not respond monitor" + type = string + default = "" +} + +variable "not_responding_threshold_warning" { + description = "Elasticsearch not responding limit (warning threshold)" + default = 3 +} + +variable "not_responding_no_data_timeframe" { + description = "Elasticsearch not responding monitor no data timeframe" + type = string + default = 10 +} + +variable "not_responding_extra_tags" { + description = "Extra tags for Elasticsearch does not respond monitor" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/database/elasticsearch/modules.tf b/.terraform/modules/datadog-monitors-system-generic/database/elasticsearch/modules.tf new file mode 100755 index 0000000..6f3dc60 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/elasticsearch/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "elasticsearch" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/database/elasticsearch/monitors-elasticsearch.tf b/.terraform/modules/datadog-monitors-system-generic/database/elasticsearch/monitors-elasticsearch.tf new file mode 100755 index 0000000..c33ab9a --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/elasticsearch/monitors-elasticsearch.tf @@ -0,0 +1,725 @@ +# +# Service Check +# +resource "datadog_monitor" "not_responding" { + count = var.not_responding_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ElasticSearch does not respond" + message = coalesce(var.not_responding_message, var.message) + type = "service check" + + query = < ${var.cluster_initializing_shards_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.cluster_initializing_shards_threshold_warning + critical = var.cluster_initializing_shards_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.cluster_initializing_shards_extra_tags) +} + +# +# Cluster Relocating Shards +# +resource "datadog_monitor" "cluster_relocating_shards" { + count = var.cluster_relocating_shards_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ElasticSearch Cluster is relocating shards" + message = coalesce(var.cluster_relocating_shards_message, var.message) + type = "metric alert" + + query = < ${var.cluster_relocating_shards_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.cluster_relocating_shards_threshold_warning + critical = var.cluster_relocating_shards_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.cluster_relocating_shards_extra_tags) +} + +# +# Cluster Unassigned Shards +# +resource "datadog_monitor" "cluster_unassigned_shards" { + count = var.cluster_unassigned_shards_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ElasticSearch Cluster has unassigned shards" + message = coalesce(var.cluster_unassigned_shards_message, var.message) + type = "metric alert" + + query = < ${var.cluster_unassigned_shards_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.cluster_unassigned_shards_threshold_warning + critical = var.cluster_unassigned_shards_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.cluster_unassigned_shards_extra_tags) +} + +# +# Free Space in nodes +# +resource "datadog_monitor" "node_free_space" { + count = var.node_free_space_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ElasticSearch free space < 10%" + message = coalesce(var.node_free_space_message, var.message) + + type = "query alert" + + query = < ${var.jvm_heap_memory_usage_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.jvm_heap_memory_usage_threshold_warning + critical = var.jvm_heap_memory_usage_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.jvm_heap_memory_usage_extra_tags) +} + +# +# JVM Memory Young Usage +# +resource "datadog_monitor" "jvm_memory_young_usage" { + count = var.jvm_memory_young_usage_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch JVM memory Young usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.jvm_memory_young_usage_message, var.message) + type = "query alert" + + query = < ${var.jvm_memory_young_usage_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.jvm_memory_young_usage_threshold_warning + critical = var.jvm_memory_young_usage_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.jvm_memory_young_usage_extra_tags) +} + +# +# JVM Memory Old Usage +# +resource "datadog_monitor" "jvm_memory_old_usage" { + count = var.jvm_memory_old_usage_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch JVM memory Old usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.jvm_memory_old_usage_message, var.message) + type = "query alert" + + query = < ${var.jvm_memory_old_usage_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.jvm_memory_old_usage_threshold_warning + critical = var.jvm_memory_old_usage_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.jvm_memory_old_usage_extra_tags) +} + +# +# JVM Garbace Collector Old Collection Latency +# +resource "datadog_monitor" "jvm_gc_old_collection_latency" { + count = var.jvm_gc_old_collection_latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch average Old-generation garbage collections latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.jvm_gc_old_collection_latency_message, var.message) + type = "query alert" + + query = < ${var.jvm_gc_old_collection_latency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.jvm_gc_old_collection_latency_threshold_warning + critical = var.jvm_gc_old_collection_latency_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.jvm_gc_old_collection_latency_extra_tags) +} + +# +# JVM Garbace Collector Young Collection Latency +# +resource "datadog_monitor" "jvm_gc_young_collection_latency" { + count = var.jvm_gc_young_collection_latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch average Young-generation garbage collections latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.jvm_gc_young_collection_latency_message, var.message) + type = "query alert" + + query = < ${var.jvm_gc_young_collection_latency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.jvm_gc_young_collection_latency_threshold_warning + critical = var.jvm_gc_young_collection_latency_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.jvm_gc_young_collection_latency_extra_tags) +} + +# +# Indexing Latency +# +resource "datadog_monitor" "indexing_latency" { + count = var.indexing_latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch average indexing latency by document {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.indexing_latency_message, var.message) + type = "query alert" + + // TODO add tags to filter by node type and do not apply this monitor on non-data nodes + query = < ${var.indexing_latency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.indexing_latency_threshold_warning + critical = var.indexing_latency_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.indexing_latency_extra_tags) +} + +# +# Flush Latency +# +resource "datadog_monitor" "flush_latency" { + count = var.flush_latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch average index flushing to disk latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.flush_latency_message, var.message) + type = "query alert" + + // TODO add tags to filter by node type and do not apply this monitor on non-data nodes + query = < ${var.flush_latency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.flush_latency_threshold_warning + critical = var.flush_latency_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.flush_latency_extra_tags) +} + +# +# Open HTTP Connections Anomaly +# +resource "datadog_monitor" "http_connections_anomaly" { + count = var.http_connections_anomaly_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch number of current open HTTP connections anomaly detected" + message = coalesce(var.http_connections_anomaly_message, var.message) + type = "query alert" + + query = <= ${var.http_connections_anomaly_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.http_connections_anomaly_threshold_warning + critical = var.http_connections_anomaly_threshold_critical + } + + monitor_threshold_windows { + trigger_window = var.http_connections_anomaly_alert_window + recovery_window = var.http_connections_anomaly_alert_window + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.http_connections_anomaly_extra_tags) +} + +# +# Query Latency +# +resource "datadog_monitor" "search_query_latency" { + count = var.search_query_latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch average search query latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.search_query_latency_message, var.message) + type = "query alert" + + // TODO add tags to filter by node type and do not apply this monitor on non-data nodes + query = < ${var.search_query_latency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.search_query_latency_threshold_warning + critical = var.search_query_latency_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.search_query_latency_extra_tags) +} + +# +# Fetch Latency +# +resource "datadog_monitor" "fetch_latency" { + count = var.fetch_latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch average search fetch latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}ms){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}ms){{/is_warning}}" + message = coalesce(var.fetch_latency_message, var.message) + type = "query alert" + + // TODO add tags to filter by node type and do not apply this monitor on non-data nodes + query = < ${var.fetch_latency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.fetch_latency_threshold_warning + critical = var.fetch_latency_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.fetch_latency_extra_tags) +} + +# +# Search Query Change +# +resource "datadog_monitor" "search_query_change" { + count = var.search_query_change_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch change alert on the number of currently active queries" + message = coalesce(var.search_query_change_message, var.message) + type = "query alert" + + query = <= ${var.search_query_change_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.search_query_change_threshold_warning + critical = var.search_query_change_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.search_query_change_extra_tags) +} + +# +# Fetch Change +# +resource "datadog_monitor" "fetch_change" { + count = var.fetch_change_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch change alert on the number of search fetches currently running" + message = coalesce(var.fetch_change_message, var.message) + type = "query alert" + + query = <= ${var.fetch_change_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.fetch_change_threshold_warning + critical = var.fetch_change_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.fetch_change_extra_tags) +} + +# +# Field Data Evictions +# +resource "datadog_monitor" "field_data_evictions_change" { + count = var.field_data_evictions_change_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch change alert on the total number of evictions from the fielddata cache" + message = coalesce(var.field_data_evictions_change_message, var.message) + type = "query alert" + + // TODO add tags to filter by node type and do not apply this monitor on non-data nodes + query = < ${var.field_data_evictions_change_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.field_data_evictions_change_threshold_warning + critical = var.field_data_evictions_change_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.field_data_evictions_change_extra_tags) +} + +# +# Query Cache Evictions +# +resource "datadog_monitor" "query_cache_evictions_change" { + count = var.query_cache_evictions_change_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch change alert on the number of query cache evictions" + message = coalesce(var.query_cache_evictions_change_message, var.message) + type = "query alert" + + // TODO add tags to filter by node type and do not apply this monitor on non-data nodes + query = < ${var.query_cache_evictions_change_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.query_cache_evictions_change_threshold_warning + critical = var.query_cache_evictions_change_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.query_cache_evictions_change_extra_tags) +} + +# +# Request Cache Evictions +# +resource "datadog_monitor" "request_cache_evictions_change" { + count = var.request_cache_evictions_change_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch change alert on the number of request cache evictions" + message = coalesce(var.request_cache_evictions_change_message, var.message) + type = "query alert" + + // TODO add tags to filter by node type and do not apply this monitor on non-data nodes + query = < ${var.request_cache_evictions_change_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.request_cache_evictions_change_threshold_warning + critical = var.request_cache_evictions_change_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.request_cache_evictions_change_extra_tags) +} + +# +# Task Time in Queue +# +resource "datadog_monitor" "task_time_in_queue_change" { + count = var.task_time_in_queue_change_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Elasticsearch change alert on the average time spent by tasks in the queue" + message = coalesce(var.task_time_in_queue_change_message, var.message) + type = "query alert" + + query = < ${var.task_time_in_queue_change_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.task_time_in_queue_change_threshold_warning + critical = var.task_time_in_queue_change_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:elasticsearch", "resource:elasticsearch", "team:claranet", "created-by:terraform"], var.task_time_in_queue_change_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/database/elasticsearch/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/database/elasticsearch/outputs.tf new file mode 100755 index 0000000..b70b9cb --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/elasticsearch/outputs.tf @@ -0,0 +1,110 @@ +output "cluster_initializing_shards_id" { + description = "id for monitor cluster_initializing_shards" + value = datadog_monitor.cluster_initializing_shards.*.id +} + +output "cluster_relocating_shards_id" { + description = "id for monitor cluster_relocating_shards" + value = datadog_monitor.cluster_relocating_shards.*.id +} + +output "cluster_status_not_green_id" { + description = "id for monitor cluster_status_not_green" + value = datadog_monitor.cluster_status_not_green.*.id +} + +output "cluster_unassigned_shards_id" { + description = "id for monitor cluster_unassigned_shards" + value = datadog_monitor.cluster_unassigned_shards.*.id +} + +output "fetch_change_id" { + description = "id for monitor fetch_change" + value = datadog_monitor.fetch_change.*.id +} + +output "fetch_latency_id" { + description = "id for monitor fetch_latency" + value = datadog_monitor.fetch_latency.*.id +} + +output "field_data_evictions_change_id" { + description = "id for monitor field_data_evictions_change" + value = datadog_monitor.field_data_evictions_change.*.id +} + +output "flush_latency_id" { + description = "id for monitor flush_latency" + value = datadog_monitor.flush_latency.*.id +} + +output "http_connections_anomaly_id" { + description = "id for monitor http_connections_anomaly" + value = datadog_monitor.http_connections_anomaly.*.id +} + +output "indexing_latency_id" { + description = "id for monitor indexing_latency" + value = datadog_monitor.indexing_latency.*.id +} + +output "jvm_gc_old_collection_latency_id" { + description = "id for monitor jvm_gc_old_collection_latency" + value = datadog_monitor.jvm_gc_old_collection_latency.*.id +} + +output "jvm_gc_young_collection_latency_id" { + description = "id for monitor jvm_gc_young_collection_latency" + value = datadog_monitor.jvm_gc_young_collection_latency.*.id +} + +output "jvm_heap_memory_usage_id" { + description = "id for monitor jvm_heap_memory_usage" + value = datadog_monitor.jvm_heap_memory_usage.*.id +} + +output "jvm_memory_old_usage_id" { + description = "id for monitor jvm_memory_old_usage" + value = datadog_monitor.jvm_memory_old_usage.*.id +} + +output "jvm_memory_young_usage_id" { + description = "id for monitor jvm_memory_young_usage" + value = datadog_monitor.jvm_memory_young_usage.*.id +} + +output "node_free_space_id" { + description = "id for monitor node_free_space" + value = datadog_monitor.node_free_space.*.id +} + +output "not_responding_id" { + description = "id for monitor not_responding" + value = datadog_monitor.not_responding.*.id +} + +output "query_cache_evictions_change_id" { + description = "id for monitor query_cache_evictions_change" + value = datadog_monitor.query_cache_evictions_change.*.id +} + +output "request_cache_evictions_change_id" { + description = "id for monitor request_cache_evictions_change" + value = datadog_monitor.request_cache_evictions_change.*.id +} + +output "search_query_change_id" { + description = "id for monitor search_query_change" + value = datadog_monitor.search_query_change.*.id +} + +output "search_query_latency_id" { + description = "id for monitor search_query_latency" + value = datadog_monitor.search_query_latency.*.id +} + +output "task_time_in_queue_change_id" { + description = "id for monitor task_time_in_queue_change" + value = datadog_monitor.task_time_in_queue_change.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/database/elasticsearch/versions.tf b/.terraform/modules/datadog-monitors-system-generic/database/elasticsearch/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/elasticsearch/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/database/mongodb/README.md b/.terraform/modules/datadog-monitors-system-generic/database/mongodb/README.md new file mode 100755 index 0000000..20ea1ee --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/mongodb/README.md @@ -0,0 +1,102 @@ +# DATABASE MONGODB DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-database-mongodb" { + source = "claranet/monitors/datadog//database/mongodb" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- MongoDB primary state +- MongoDB replication lag +- MongoDB secondary missing +- MongoDB too much servers or wrong monitoring config + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | +| [filter-tags-secondary](#module\_filter-tags-secondary) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.mongodb_primary](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mongodb_replication](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mongodb_secondary](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mongodb_server_count](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [mongodb\_desired\_servers\_count](#input\_mongodb\_desired\_servers\_count) | Number of servers that should be instanciated for this cluster | `number` | `3` | no | +| [mongodb\_lag\_critical](#input\_mongodb\_lag\_critical) | Critical replication lag in s | `number` | `5` | no | +| [mongodb\_lag\_warning](#input\_mongodb\_lag\_warning) | Warn replication lag in s | `number` | `2` | no | +| [mongodb\_primary\_aggregator](#input\_mongodb\_primary\_aggregator) | Monitor aggregator for MongoDB primary state [available values: min, max] | `string` | `"max"` | no | +| [mongodb\_primary\_enabled](#input\_mongodb\_primary\_enabled) | Flag to enable MongoDB primary state monitor | `string` | `"true"` | no | +| [mongodb\_primary\_extra\_tags](#input\_mongodb\_primary\_extra\_tags) | Extra tags for MongoDB primary state monitor | `list(string)` | `[]` | no | +| [mongodb\_primary\_message](#input\_mongodb\_primary\_message) | Custom message for MongoDB primary monitor | `string` | `""` | no | +| [mongodb\_primary\_no\_data\_timeframe](#input\_mongodb\_primary\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [mongodb\_primary\_timeframe](#input\_mongodb\_primary\_timeframe) | Monitor timeframe for MongoDB wrong state for primary node [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1m"` | no | +| [mongodb\_replication\_aggregator](#input\_mongodb\_replication\_aggregator) | Monitor aggregator for MongoDB replication lag [available values: min, max, sum or avg] | `string` | `"avg"` | no | +| [mongodb\_replication\_enabled](#input\_mongodb\_replication\_enabled) | Flag to enable MongoDB replication lag monitor | `string` | `"true"` | no | +| [mongodb\_replication\_extra\_tags](#input\_mongodb\_replication\_extra\_tags) | Extra tags for MongoDB replication lag monitor | `list(string)` | `[]` | no | +| [mongodb\_replication\_message](#input\_mongodb\_replication\_message) | Custom message for MongoDB replication monitor | `string` | `""` | no | +| [mongodb\_replication\_timeframe](#input\_mongodb\_replication\_timeframe) | Monitor timeframe for MongoDB replication lag [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1m"` | no | +| [mongodb\_secondary\_aggregator](#input\_mongodb\_secondary\_aggregator) | Monitor aggregator for MongoDB secondary state [available values: min, max] | `string` | `"max"` | no | +| [mongodb\_secondary\_enabled](#input\_mongodb\_secondary\_enabled) | Flag to enable MongoDB secondary state monitor | `string` | `"true"` | no | +| [mongodb\_secondary\_extra\_tags](#input\_mongodb\_secondary\_extra\_tags) | Extra tags for MongoDB secondary state monitor | `list(string)` | `[]` | no | +| [mongodb\_secondary\_message](#input\_mongodb\_secondary\_message) | Custom message for MongoDB secondary monitor | `string` | `""` | no | +| [mongodb\_secondary\_timeframe](#input\_mongodb\_secondary\_timeframe) | Monitor timeframe for MongoDB wrong state for secondaries nodes [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [mongodb\_server\_count\_aggregator](#input\_mongodb\_server\_count\_aggregator) | Monitor aggregator for MongoDB server count [available values: min, max] | `string` | `"min"` | no | +| [mongodb\_server\_count\_enabled](#input\_mongodb\_server\_count\_enabled) | Flag to enable MongoDB server count monitor | `string` | `"true"` | no | +| [mongodb\_server\_count\_message](#input\_mongodb\_server\_count\_message) | Custom message for MongoDB server count | `string` | `""` | no | +| [mongodb\_server\_count\_timeframe](#input\_mongodb\_server\_count\_timeframe) | Monitor timeframe for MongoDB wrong server count [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [mongodb\_primary\_id](#output\_mongodb\_primary\_id) | id for monitor mongodb\_primary | +| [mongodb\_replication\_id](#output\_mongodb\_replication\_id) | id for monitor mongodb\_replication | +| [mongodb\_secondary\_id](#output\_mongodb\_secondary\_id) | id for monitor mongodb\_secondary | +| [mongodb\_server\_count\_id](#output\_mongodb\_server\_count\_id) | id for monitor mongodb\_server\_count | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/mongo/](https://docs.datadoghq.com/integrations/mongo/) +MongoDB documentation: [https://docs.mongodb.com/manual/administration/monitoring/](https://docs.mongodb.com/manual/administration/monitoring/) diff --git a/.terraform/modules/datadog-monitors-system-generic/database/mongodb/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/database/mongodb/inputs.tf new file mode 100755 index 0000000..6e62fd0 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/mongodb/inputs.tf @@ -0,0 +1,181 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "mongodb_primary_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "mongodb_desired_servers_count" { + description = "Number of servers that should be instanciated for this cluster" + default = 3 +} + +variable "mongodb_primary_timeframe" { + description = "Monitor timeframe for MongoDB wrong state for primary node [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1m" +} + +variable "mongodb_secondary_timeframe" { + description = "Monitor timeframe for MongoDB wrong state for secondaries nodes [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "mongodb_server_count_timeframe" { + description = "Monitor timeframe for MongoDB wrong server count [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "mongodb_replication_timeframe" { + description = "Monitor timeframe for MongoDB replication lag [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1m" +} + +variable "mongodb_lag_warning" { + description = "Warn replication lag in s" + default = 2 +} + +variable "mongodb_lag_critical" { + description = "Critical replication lag in s" + default = 5 +} + +variable "mongodb_primary_enabled" { + description = "Flag to enable MongoDB primary state monitor" + type = string + default = "true" +} + +variable "mongodb_primary_extra_tags" { + description = "Extra tags for MongoDB primary state monitor" + type = list(string) + default = [] +} + +variable "mongodb_secondary_enabled" { + description = "Flag to enable MongoDB secondary state monitor" + type = string + default = "true" +} + +variable "mongodb_secondary_extra_tags" { + description = "Extra tags for MongoDB secondary state monitor" + type = list(string) + default = [] +} + +variable "mongodb_server_count_enabled" { + description = "Flag to enable MongoDB server count monitor" + type = string + default = "true" +} + +variable "mongodb_replication_enabled" { + description = "Flag to enable MongoDB replication lag monitor" + type = string + default = "true" +} + +variable "mongodb_replication_extra_tags" { + description = "Extra tags for MongoDB replication lag monitor" + type = list(string) + default = [] +} + +variable "mongodb_primary_message" { + description = "Custom message for MongoDB primary monitor" + type = string + default = "" +} + +variable "mongodb_secondary_message" { + description = "Custom message for MongoDB secondary monitor" + type = string + default = "" +} + +variable "mongodb_server_count_message" { + description = "Custom message for MongoDB server count" + type = string + default = "" +} + +variable "mongodb_replication_message" { + description = "Custom message for MongoDB replication monitor" + type = string + default = "" +} + +variable "mongodb_primary_aggregator" { + description = "Monitor aggregator for MongoDB primary state [available values: min, max]" + type = string + default = "max" +} + +variable "mongodb_secondary_aggregator" { + description = "Monitor aggregator for MongoDB secondary state [available values: min, max]" + type = string + default = "max" +} + +variable "mongodb_server_count_aggregator" { + description = "Monitor aggregator for MongoDB server count [available values: min, max]" + type = string + default = "min" +} + +variable "mongodb_replication_aggregator" { + description = "Monitor aggregator for MongoDB replication lag [available values: min, max, sum or avg]" + type = string + default = "avg" +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/database/mongodb/modules.tf b/.terraform/modules/datadog-monitors-system-generic/database/mongodb/modules.tf new file mode 100755 index 0000000..1ff409d --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/mongodb/modules.tf @@ -0,0 +1,21 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "mongodb" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + +module "filter-tags-secondary" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "mongodb" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["replset_state:secondary"] +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/database/mongodb/monitors-mongo.tf b/.terraform/modules/datadog-monitors-system-generic/database/mongodb/monitors-mongo.tf new file mode 100755 index 0000000..6f01088 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/mongodb/monitors-mongo.tf @@ -0,0 +1,111 @@ +resource "datadog_monitor" "mongodb_primary" { + count = var.mongodb_primary_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] MongoDB primary state" + message = coalesce(var.mongodb_primary_message, var.message) + type = "metric alert" + + query = <= 2 +EOQ + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = var.notify_no_data + no_data_timeframe = var.mongodb_primary_no_data_timeframe + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + require_full_window = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mongo", "resource:mongodb", "team:claranet", "created-by:terraform"], var.mongodb_primary_extra_tags) +} + +resource "datadog_monitor" "mongodb_secondary" { + count = var.mongodb_secondary_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] MongoDB secondary missing" + message = coalesce(var.mongodb_secondary_message, var.message) + type = "query alert" + + query = < 1 +EOQ + + monitor_thresholds { + critical = 1 + warning = 0 + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + require_full_window = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mongo", "resource:mongodb", "team:claranet", "created-by:terraform"], var.mongodb_secondary_extra_tags) +} + +resource "datadog_monitor" "mongodb_server_count" { + count = var.mongodb_server_count_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] MongoDB too much servers or wrong monitoring config" + message = coalesce(var.mongodb_server_count_message, var.message) + type = "metric alert" + + query = < 99 +EOQ + + monitor_thresholds { + critical = 99 + warning = var.mongodb_desired_servers_count + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + require_full_window = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mongo", "resource:mongodb", "team:claranet", "created-by:terraform"], var.mongodb_secondary_extra_tags) +} + +resource "datadog_monitor" "mongodb_replication" { + count = var.mongodb_replication_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] MongoDB replication lag" + message = coalesce(var.mongodb_replication_message, var.message) + type = "metric alert" + + query = < ${var.mongodb_lag_critical} +EOQ + + monitor_thresholds { + critical = var.mongodb_lag_critical + warning = var.mongodb_lag_warning + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + require_full_window = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mongo", "resource:mongodb", "team:claranet", "created-by:terraform"], var.mongodb_replication_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/database/mongodb/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/database/mongodb/outputs.tf new file mode 100755 index 0000000..64271a4 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/mongodb/outputs.tf @@ -0,0 +1,20 @@ +output "mongodb_primary_id" { + description = "id for monitor mongodb_primary" + value = datadog_monitor.mongodb_primary.*.id +} + +output "mongodb_replication_id" { + description = "id for monitor mongodb_replication" + value = datadog_monitor.mongodb_replication.*.id +} + +output "mongodb_secondary_id" { + description = "id for monitor mongodb_secondary" + value = datadog_monitor.mongodb_secondary.*.id +} + +output "mongodb_server_count_id" { + description = "id for monitor mongodb_server_count" + value = datadog_monitor.mongodb_server_count.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/database/mongodb/versions.tf b/.terraform/modules/datadog-monitors-system-generic/database/mongodb/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/mongodb/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/database/mysql/README.md b/.terraform/modules/datadog-monitors-system-generic/database/mysql/README.md new file mode 100755 index 0000000..be7c9c8 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/mysql/README.md @@ -0,0 +1,178 @@ +# DATABASE MYSQL DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-database-mysql" { + source = "claranet/monitors/datadog//database/mysql" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Mysql Aborted connects +- Mysql Connections limit +- Mysql Innodb buffer pool efficiency +- Mysql Innodb buffer pool utilization +- Mysql queries changed abnormally +- Mysql replication lag (disabled by default) +- Mysql replication status changed abnormally (disabled by default) +- Mysql server does not respond +- Mysql Slow queries +- Mysql threads changed abnormally + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.mysql_aborted](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_availability](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_connection](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_pool_efficiency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_pool_utilization](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_questions_anomaly](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_replication_lag](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_replication_status](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_slow](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.mysql_threads_anomaly](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [mysql\_aborted\_enabled](#input\_mysql\_aborted\_enabled) | Flag to enable MySQL aborted connects monitor | `string` | `"true"` | no | +| [mysql\_aborted\_extra\_tags](#input\_mysql\_aborted\_extra\_tags) | Extra tags for MySQL aborted connects monitor | `list(string)` | `[]` | no | +| [mysql\_aborted\_message](#input\_mysql\_aborted\_message) | Custom message for MySQL aborted connects monitor | `string` | `""` | no | +| [mysql\_aborted\_threshold\_critical](#input\_mysql\_aborted\_threshold\_critical) | Maximum critical acceptable percent of aborted connects | `number` | `10` | no | +| [mysql\_aborted\_threshold\_warning](#input\_mysql\_aborted\_threshold\_warning) | Maximum warning acceptable percent of aborted connects | `number` | `5` | no | +| [mysql\_aborted\_time\_aggregator](#input\_mysql\_aborted\_time\_aggregator) | Monitor time aggregator for MySQL aborted connects monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [mysql\_aborted\_timeframe](#input\_mysql\_aborted\_timeframe) | Monitor timeframe for MySQL aborted connects monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_10m"` | no | +| [mysql\_availability\_enabled](#input\_mysql\_availability\_enabled) | Flag to enable Mysql availability monitor | `string` | `"true"` | no | +| [mysql\_availability\_extra\_tags](#input\_mysql\_availability\_extra\_tags) | Extra tags for Mysql availability monitor | `list(string)` | `[]` | no | +| [mysql\_availability\_message](#input\_mysql\_availability\_message) | Custom message for Mysql availability monitor | `string` | `""` | no | +| [mysql\_availability\_no\_data\_timeframe](#input\_mysql\_availability\_no\_data\_timeframe) | Mysql availability monitor no data timeframe | `string` | `10` | no | +| [mysql\_availability\_threshold\_warning](#input\_mysql\_availability\_threshold\_warning) | Mysql availability monitor (warning threshold) | `string` | `3` | no | +| [mysql\_connection\_enabled](#input\_mysql\_connection\_enabled) | Flag to enable MySQL connection monitor | `string` | `"true"` | no | +| [mysql\_connection\_extra\_tags](#input\_mysql\_connection\_extra\_tags) | Extra tags for MySQL connection monitor | `list(string)` | `[]` | no | +| [mysql\_connection\_message](#input\_mysql\_connection\_message) | Custom message for MySQL connection monitor | `string` | `""` | no | +| [mysql\_connection\_threshold\_critical](#input\_mysql\_connection\_threshold\_critical) | Maximum critical acceptable percent of connections | `number` | `80` | no | +| [mysql\_connection\_threshold\_warning](#input\_mysql\_connection\_threshold\_warning) | Maximum warning acceptable percent of connections | `number` | `70` | no | +| [mysql\_connection\_time\_aggregator](#input\_mysql\_connection\_time\_aggregator) | Monitor time aggregator for MySQL connection monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [mysql\_connection\_timeframe](#input\_mysql\_connection\_timeframe) | Monitor timeframe for MySQL connection monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_10m"` | no | +| [mysql\_pool\_efficiency\_enabled](#input\_mysql\_pool\_efficiency\_enabled) | Flag to enable MySQL innodb buffer pool efficiency monitor | `string` | `"true"` | no | +| [mysql\_pool\_efficiency\_extra\_tags](#input\_mysql\_pool\_efficiency\_extra\_tags) | Extra tags for MySQL innodb buffer pool efficiency monitor | `list(string)` | `[]` | no | +| [mysql\_pool\_efficiency\_message](#input\_mysql\_pool\_efficiency\_message) | Custom message for MySQL innodb buffer pool efficiency monitor | `string` | `""` | no | +| [mysql\_pool\_efficiency\_threshold\_critical](#input\_mysql\_pool\_efficiency\_threshold\_critical) | Maximum critical acceptable percent of innodb buffer pool efficiency | `number` | `30` | no | +| [mysql\_pool\_efficiency\_threshold\_warning](#input\_mysql\_pool\_efficiency\_threshold\_warning) | Maximum warning acceptable percent of innodb buffer pool efficiency | `number` | `20` | no | +| [mysql\_pool\_efficiency\_time\_aggregator](#input\_mysql\_pool\_efficiency\_time\_aggregator) | Monitor time aggregator for MySQL innodb buffer pool efficiency monitor [available values: min, max or avg] | `string` | `"min"` | no | +| [mysql\_pool\_efficiency\_timeframe](#input\_mysql\_pool\_efficiency\_timeframe) | Monitor timeframe for MySQL innodb buffer pool efficiency monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1h"` | no | +| [mysql\_pool\_utilization\_enabled](#input\_mysql\_pool\_utilization\_enabled) | Flag to enable MySQL innodb buffer pool utilization monitor | `string` | `"true"` | no | +| [mysql\_pool\_utilization\_extra\_tags](#input\_mysql\_pool\_utilization\_extra\_tags) | Extra tags for MySQL innodb buffer pool utilization monitor | `list(string)` | `[]` | no | +| [mysql\_pool\_utilization\_message](#input\_mysql\_pool\_utilization\_message) | Custom message for MySQL innodb buffer pool utilization monitor | `string` | `""` | no | +| [mysql\_pool\_utilization\_threshold\_critical](#input\_mysql\_pool\_utilization\_threshold\_critical) | Maximum critical acceptable percent of innodb buffer pool utilization | `number` | `95` | no | +| [mysql\_pool\_utilization\_threshold\_warning](#input\_mysql\_pool\_utilization\_threshold\_warning) | Maximum warning acceptable percent of innodb buffer pool utilization | `number` | `80` | no | +| [mysql\_pool\_utilization\_time\_aggregator](#input\_mysql\_pool\_utilization\_time\_aggregator) | Monitor time aggregator for MySQL innodb buffer pool utilization monitor [available values: min, max or avg] | `string` | `"min"` | no | +| [mysql\_pool\_utilization\_timeframe](#input\_mysql\_pool\_utilization\_timeframe) | Monitor timeframe for MySQL innodb buffer pool utilization monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1h"` | no | +| [mysql\_questions\_alert\_window](#input\_mysql\_questions\_alert\_window) | Alert window. | `string` | `"last_15m"` | no | +| [mysql\_questions\_count\_default\_zero](#input\_mysql\_questions\_count\_default\_zero) | Count default zero. | `string` | `"true"` | no | +| [mysql\_questions\_detection\_algorithm](#input\_mysql\_questions\_detection\_algorithm) | Anomaly Detection Algorithm used | `string` | `"agile"` | no | +| [mysql\_questions\_deviations](#input\_mysql\_questions\_deviations) | Deviations to detect the anomaly | `string` | `5` | no | +| [mysql\_questions\_direction](#input\_mysql\_questions\_direction) | Direction of the anomaly. It can be both, below or above. | `string` | `"both"` | no | +| [mysql\_questions\_enabled](#input\_mysql\_questions\_enabled) | Flag to enable mysql queries monitor | `string` | `"true"` | no | +| [mysql\_questions\_extra\_tags](#input\_mysql\_questions\_extra\_tags) | Extra tags for MySQL queries monitor | `list(string)` | `[]` | no | +| [mysql\_questions\_interval](#input\_mysql\_questions\_interval) | Interval. | `string` | `60` | no | +| [mysql\_questions\_message](#input\_mysql\_questions\_message) | Custom message for MySQL queries monitor | `string` | `""` | no | +| [mysql\_questions\_seasonality](#input\_mysql\_questions\_seasonality) | Seasonality of the algorithm | `string` | `"daily"` | no | +| [mysql\_questions\_threshold\_critical](#input\_mysql\_questions\_threshold\_critical) | Maximum critical acceptable number of queries | `number` | `1` | no | +| [mysql\_questions\_time\_aggregator](#input\_mysql\_questions\_time\_aggregator) | Monitor time aggregator for MySQL queries monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [mysql\_questions\_timeframe](#input\_mysql\_questions\_timeframe) | Monitor timeframe for MySQL queries monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_4h"` | no | +| [mysql\_replication\_lag\_enabled](#input\_mysql\_replication\_lag\_enabled) | Flag to enable mysql replication lag monitor | `string` | `"false"` | no | +| [mysql\_replication\_lag\_extra\_tags](#input\_mysql\_replication\_lag\_extra\_tags) | Extra tags for MySQL replication lag monitor | `list(string)` | `[]` | no | +| [mysql\_replication\_lag\_message](#input\_mysql\_replication\_lag\_message) | Custom message for MySQL replication lag monitor | `string` | `""` | no | +| [mysql\_replication\_lag\_threshold\_critical](#input\_mysql\_replication\_lag\_threshold\_critical) | Maximum critical acceptable seconds of replication lag | `number` | `200` | no | +| [mysql\_replication\_lag\_threshold\_warning](#input\_mysql\_replication\_lag\_threshold\_warning) | Maximum warning acceptable seconds of replication lag | `number` | `100` | no | +| [mysql\_replication\_lag\_time\_aggregator](#input\_mysql\_replication\_lag\_time\_aggregator) | Monitor time aggregator for MySQL replication lag monitor [available values: min, max or avg] | `string` | `"min"` | no | +| [mysql\_replication\_lag\_timeframe](#input\_mysql\_replication\_lag\_timeframe) | Monitor timeframe for MySQL replication lag monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [mysql\_replication\_status\_enabled](#input\_mysql\_replication\_status\_enabled) | Flag to enable mysql replication status monitor | `string` | `"false"` | no | +| [mysql\_replication\_status\_extra\_tags](#input\_mysql\_replication\_status\_extra\_tags) | Extra tags for MySQL replication status monitor | `list(string)` | `[]` | no | +| [mysql\_replication\_status\_message](#input\_mysql\_replication\_status\_message) | Custom message for MySQL replication status monitor | `string` | `""` | no | +| [mysql\_replication\_status\_time\_aggregator](#input\_mysql\_replication\_status\_time\_aggregator) | Monitor time aggregator for MySQL replication status monitor [available values: min, max or avg] | `string` | `"min"` | no | +| [mysql\_replication\_status\_timeframe](#input\_mysql\_replication\_status\_timeframe) | Monitor timeframe for MySQL replication status monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [mysql\_slow\_enabled](#input\_mysql\_slow\_enabled) | Flag to enable MySQL slow queries monitor | `string` | `"true"` | no | +| [mysql\_slow\_extra\_tags](#input\_mysql\_slow\_extra\_tags) | Extra tags for MySQL slow queries monitor | `list(string)` | `[]` | no | +| [mysql\_slow\_message](#input\_mysql\_slow\_message) | Custom message for MySQL slow queries monitor | `string` | `""` | no | +| [mysql\_slow\_threshold\_critical](#input\_mysql\_slow\_threshold\_critical) | Maximum critical acceptable percent of slow queries | `number` | `20` | no | +| [mysql\_slow\_threshold\_warning](#input\_mysql\_slow\_threshold\_warning) | Maximum warning acceptable percent of slow queries | `number` | `5` | no | +| [mysql\_slow\_time\_aggregator](#input\_mysql\_slow\_time\_aggregator) | Monitor time aggregator for MySQL slow queries monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [mysql\_slow\_timeframe](#input\_mysql\_slow\_timeframe) | Monitor timeframe for MySQL slow queries monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [mysql\_threads\_alert\_window](#input\_mysql\_threads\_alert\_window) | Alert window. | `string` | `"last_15m"` | no | +| [mysql\_threads\_count\_default\_zero](#input\_mysql\_threads\_count\_default\_zero) | Count default zero. | `string` | `"true"` | no | +| [mysql\_threads\_detection\_algorithm](#input\_mysql\_threads\_detection\_algorithm) | Anomaly Detection Algorithm used | `string` | `"basic"` | no | +| [mysql\_threads\_deviations](#input\_mysql\_threads\_deviations) | Deviations to detect the anomaly | `string` | `2` | no | +| [mysql\_threads\_direction](#input\_mysql\_threads\_direction) | Direction of the anomaly. It can be both, below or above. | `string` | `"above"` | no | +| [mysql\_threads\_enabled](#input\_mysql\_threads\_enabled) | Flag to enable mysql threads monitor | `string` | `"true"` | no | +| [mysql\_threads\_extra\_tags](#input\_mysql\_threads\_extra\_tags) | Extra tags for MySQL threads monitor | `list(string)` | `[]` | no | +| [mysql\_threads\_interval](#input\_mysql\_threads\_interval) | Interval. | `string` | `60` | no | +| [mysql\_threads\_message](#input\_mysql\_threads\_message) | Custom message for MySQL threads monitor | `string` | `""` | no | +| [mysql\_threads\_seasonality](#input\_mysql\_threads\_seasonality) | Seasonality of the algorithm | `string` | `"daily"` | no | +| [mysql\_threads\_threshold\_critical](#input\_mysql\_threads\_threshold\_critical) | Maximum critical acceptable number of threads | `number` | `1` | no | +| [mysql\_threads\_time\_aggregator](#input\_mysql\_threads\_time\_aggregator) | Monitor time aggregator for MySQL threads monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [mysql\_threads\_timeframe](#input\_mysql\_threads\_timeframe) | Monitor timeframe for MySQL threads monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_4h"` | no | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the metric evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [mysql\_aborted\_id](#output\_mysql\_aborted\_id) | id for monitor mysql\_aborted | +| [mysql\_availability\_id](#output\_mysql\_availability\_id) | id for monitor mysql\_availability | +| [mysql\_connection\_id](#output\_mysql\_connection\_id) | id for monitor mysql\_connection | +| [mysql\_pool\_efficiency\_id](#output\_mysql\_pool\_efficiency\_id) | id for monitor mysql\_pool\_efficiency | +| [mysql\_pool\_utilization\_id](#output\_mysql\_pool\_utilization\_id) | id for monitor mysql\_pool\_utilization | +| [mysql\_questions\_anomaly\_id](#output\_mysql\_questions\_anomaly\_id) | id for monitor mysql\_questions\_anomaly | +| [mysql\_replication\_lag\_id](#output\_mysql\_replication\_lag\_id) | id for monitor mysql\_replication\_lag | +| [mysql\_replication\_status\_id](#output\_mysql\_replication\_status\_id) | id for monitor mysql\_replication\_status | +| [mysql\_slow\_id](#output\_mysql\_slow\_id) | id for monitor mysql\_slow | +| [mysql\_threads\_anomaly\_id](#output\_mysql\_threads\_anomaly\_id) | id for monitor mysql\_threads\_anomaly | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/mysql/](https://docs.datadoghq.com/integrations/mysql/) + +## Notes + +It could be not possible to modify `innodb_buffer_pool_size` or `innodb_buffer_pool_instances` mysql parameters (i.e. cloudsql). +In this case, InnoDB Pool monitors could be less useful for optimization even if they could inform when an instance should be upsized. diff --git a/.terraform/modules/datadog-monitors-system-generic/database/mysql/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/database/mysql/inputs.tf new file mode 100755 index 0000000..1de13b3 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/mysql/inputs.tf @@ -0,0 +1,539 @@ +variable "environment" { + description = "Environment" + type = string +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds for the metric evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# MySQL specific + +################################# +### MySQL availability ### +################################# + +variable "mysql_availability_enabled" { + description = "Flag to enable Mysql availability monitor" + type = string + default = "true" +} + +variable "mysql_availability_extra_tags" { + description = "Extra tags for Mysql availability monitor" + type = list(string) + default = [] +} + +variable "mysql_availability_message" { + description = "Custom message for Mysql availability monitor" + type = string + default = "" +} + +variable "mysql_availability_threshold_warning" { + description = "Mysql availability monitor (warning threshold)" + type = string + default = 3 +} + +variable "mysql_availability_no_data_timeframe" { + description = "Mysql availability monitor no data timeframe" + type = string + default = 10 +} + +################################# +### MySQL connections ### +################################# + +variable "mysql_connection_enabled" { + description = "Flag to enable MySQL connection monitor" + type = string + default = "true" +} + +variable "mysql_connection_extra_tags" { + description = "Extra tags for MySQL connection monitor" + type = list(string) + default = [] +} + +variable "mysql_connection_message" { + description = "Custom message for MySQL connection monitor" + type = string + default = "" +} + +variable "mysql_connection_threshold_critical" { + default = 80 + description = "Maximum critical acceptable percent of connections" +} + +variable "mysql_connection_threshold_warning" { + default = 70 + description = "Maximum warning acceptable percent of connections" +} + +variable "mysql_connection_time_aggregator" { + description = "Monitor time aggregator for MySQL connection monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "mysql_connection_timeframe" { + description = "Monitor timeframe for MySQL connection monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_10m" +} + +################################# +### MySQL aborted connects ### +################################# + +variable "mysql_aborted_enabled" { + description = "Flag to enable MySQL aborted connects monitor" + type = string + default = "true" +} + +variable "mysql_aborted_extra_tags" { + description = "Extra tags for MySQL aborted connects monitor" + type = list(string) + default = [] +} + +variable "mysql_aborted_message" { + description = "Custom message for MySQL aborted connects monitor" + type = string + default = "" +} + +variable "mysql_aborted_threshold_critical" { + default = 10 + description = "Maximum critical acceptable percent of aborted connects" +} + +variable "mysql_aborted_threshold_warning" { + default = 5 + description = "Maximum warning acceptable percent of aborted connects" +} + +variable "mysql_aborted_time_aggregator" { + description = "Monitor time aggregator for MySQL aborted connects monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "mysql_aborted_timeframe" { + description = "Monitor timeframe for MySQL aborted connects monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_10m" +} + +################################# +### MySQL slow queries ### +################################# + +variable "mysql_slow_enabled" { + description = "Flag to enable MySQL slow queries monitor" + type = string + default = "true" +} + +variable "mysql_slow_extra_tags" { + description = "Extra tags for MySQL slow queries monitor" + type = list(string) + default = [] +} + +variable "mysql_slow_message" { + description = "Custom message for MySQL slow queries monitor" + type = string + default = "" +} + +variable "mysql_slow_threshold_critical" { + default = 20 + description = "Maximum critical acceptable percent of slow queries" +} + +variable "mysql_slow_threshold_warning" { + default = 5 + description = "Maximum warning acceptable percent of slow queries" +} + +variable "mysql_slow_time_aggregator" { + description = "Monitor time aggregator for MySQL slow queries monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "mysql_slow_timeframe" { + description = "Monitor timeframe for MySQL slow queries monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +################################# +# MySQL innodb pool efficiency # +################################# + +variable "mysql_pool_efficiency_enabled" { + description = "Flag to enable MySQL innodb buffer pool efficiency monitor" + type = string + default = "true" +} + +variable "mysql_pool_efficiency_extra_tags" { + description = "Extra tags for MySQL innodb buffer pool efficiency monitor" + type = list(string) + default = [] +} + +variable "mysql_pool_efficiency_message" { + description = "Custom message for MySQL innodb buffer pool efficiency monitor" + type = string + default = "" +} + +variable "mysql_pool_efficiency_threshold_critical" { + default = 30 + description = "Maximum critical acceptable percent of innodb buffer pool efficiency" +} + +variable "mysql_pool_efficiency_threshold_warning" { + default = 20 + description = "Maximum warning acceptable percent of innodb buffer pool efficiency" +} + +variable "mysql_pool_efficiency_time_aggregator" { + description = "Monitor time aggregator for MySQL innodb buffer pool efficiency monitor [available values: min, max or avg]" + type = string + default = "min" +} + +variable "mysql_pool_efficiency_timeframe" { + description = "Monitor timeframe for MySQL innodb buffer pool efficiency monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1h" +} + +################################# +# MySQL innodb pool utilization # +################################# + +variable "mysql_pool_utilization_enabled" { + description = "Flag to enable MySQL innodb buffer pool utilization monitor" + type = string + default = "true" +} + +variable "mysql_pool_utilization_extra_tags" { + description = "Extra tags for MySQL innodb buffer pool utilization monitor" + type = list(string) + default = [] +} + +variable "mysql_pool_utilization_message" { + description = "Custom message for MySQL innodb buffer pool utilization monitor" + type = string + default = "" +} + +variable "mysql_pool_utilization_threshold_critical" { + default = 95 + description = "Maximum critical acceptable percent of innodb buffer pool utilization" +} + +variable "mysql_pool_utilization_threshold_warning" { + default = 80 + description = "Maximum warning acceptable percent of innodb buffer pool utilization" +} + +variable "mysql_pool_utilization_time_aggregator" { + description = "Monitor time aggregator for MySQL innodb buffer pool utilization monitor [available values: min, max or avg]" + type = string + default = "min" +} + +variable "mysql_pool_utilization_timeframe" { + description = "Monitor timeframe for MySQL innodb buffer pool utilization monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1h" +} + +################################# +### MySQL threads ### +################################# + +variable "mysql_threads_enabled" { + description = "Flag to enable mysql threads monitor" + type = string + default = "true" +} + +variable "mysql_threads_extra_tags" { + description = "Extra tags for MySQL threads monitor" + type = list(string) + default = [] +} + +variable "mysql_threads_message" { + description = "Custom message for MySQL threads monitor" + type = string + default = "" +} + +variable "mysql_threads_threshold_critical" { + default = 1 + description = "Maximum critical acceptable number of threads" +} + +variable "mysql_threads_detection_algorithm" { + description = "Anomaly Detection Algorithm used" + type = string + default = "basic" +} + +variable "mysql_threads_deviations" { + description = "Deviations to detect the anomaly" + type = string + default = 2 +} + +variable "mysql_threads_direction" { + description = "Direction of the anomaly. It can be both, below or above." + type = string + default = "above" +} + +variable "mysql_threads_alert_window" { + description = "Alert window." + type = string + default = "last_15m" +} + +variable "mysql_threads_interval" { + description = "Interval." + type = string + default = 60 +} + +variable "mysql_threads_count_default_zero" { + description = "Count default zero." + type = string + default = "true" +} + +variable "mysql_threads_seasonality" { + description = "Seasonality of the algorithm" + type = string + default = "daily" +} + +variable "mysql_threads_time_aggregator" { + description = "Monitor time aggregator for MySQL threads monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "mysql_threads_timeframe" { + description = "Monitor timeframe for MySQL threads monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_4h" +} + +################################# +### MySQL queries ### +################################# + +variable "mysql_questions_enabled" { + description = "Flag to enable mysql queries monitor" + type = string + default = "true" +} + +variable "mysql_questions_extra_tags" { + description = "Extra tags for MySQL queries monitor" + type = list(string) + default = [] +} + +variable "mysql_questions_message" { + description = "Custom message for MySQL queries monitor" + type = string + default = "" +} + +variable "mysql_questions_threshold_critical" { + default = 1 + description = "Maximum critical acceptable number of queries" +} + +variable "mysql_questions_detection_algorithm" { + description = "Anomaly Detection Algorithm used" + type = string + default = "agile" +} + +variable "mysql_questions_deviations" { + description = "Deviations to detect the anomaly" + type = string + default = 5 +} + +variable "mysql_questions_direction" { + description = "Direction of the anomaly. It can be both, below or above." + type = string + default = "both" +} + +variable "mysql_questions_alert_window" { + description = "Alert window." + type = string + default = "last_15m" +} + +variable "mysql_questions_interval" { + description = "Interval." + type = string + default = 60 +} + +variable "mysql_questions_count_default_zero" { + description = "Count default zero." + type = string + default = "true" +} + +variable "mysql_questions_seasonality" { + description = "Seasonality of the algorithm" + type = string + default = "daily" +} + +variable "mysql_questions_time_aggregator" { + description = "Monitor time aggregator for MySQL queries monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "mysql_questions_timeframe" { + description = "Monitor timeframe for MySQL queries monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_4h" +} + +################################# +### MySQL replication lag ### +################################# + +variable "mysql_replication_lag_enabled" { + description = "Flag to enable mysql replication lag monitor" + type = string + default = "false" +} + +variable "mysql_replication_lag_extra_tags" { + description = "Extra tags for MySQL replication lag monitor" + type = list(string) + default = [] +} + +variable "mysql_replication_lag_message" { + description = "Custom message for MySQL replication lag monitor" + type = string + default = "" +} + +variable "mysql_replication_lag_threshold_warning" { + default = 100 + description = "Maximum warning acceptable seconds of replication lag" +} + +variable "mysql_replication_lag_threshold_critical" { + default = 200 + description = "Maximum critical acceptable seconds of replication lag" +} + +variable "mysql_replication_lag_time_aggregator" { + description = "Monitor time aggregator for MySQL replication lag monitor [available values: min, max or avg]" + type = string + default = "min" +} + +variable "mysql_replication_lag_timeframe" { + description = "Monitor timeframe for MySQL replication lag monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +################################### +### MySQL replication status ### +################################### + +variable "mysql_replication_status_enabled" { + description = "Flag to enable mysql replication status monitor" + type = string + default = "false" +} + +variable "mysql_replication_status_extra_tags" { + description = "Extra tags for MySQL replication status monitor" + type = list(string) + default = [] +} + +variable "mysql_replication_status_message" { + description = "Custom message for MySQL replication status monitor" + type = string + default = "" +} + +variable "mysql_replication_status_time_aggregator" { + description = "Monitor time aggregator for MySQL replication status monitor [available values: min, max or avg]" + type = string + default = "min" +} + +variable "mysql_replication_status_timeframe" { + description = "Monitor timeframe for MySQL replication status monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/database/mysql/modules.tf b/.terraform/modules/datadog-monitors-system-generic/database/mysql/modules.tf new file mode 100755 index 0000000..37d1850 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/mysql/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "mysql" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/database/mysql/monitors-mysql.tf b/.terraform/modules/datadog-monitors-system-generic/database/mysql/monitors-mysql.tf new file mode 100755 index 0000000..5534907 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/mysql/monitors-mysql.tf @@ -0,0 +1,309 @@ +resource "datadog_monitor" "mysql_availability" { + count = var.mysql_availability_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql server does not respond" + message = coalesce(var.mysql_availability_message, var.message) + type = "service check" + + query = < ${var.mysql_connection_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.mysql_connection_threshold_warning + critical = var.mysql_connection_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mysql", "resource:mysql", "team:claranet", "created-by:terraform"], var.mysql_connection_extra_tags) +} + +resource "datadog_monitor" "mysql_aborted" { + count = var.mysql_aborted_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql Aborted connects {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.mysql_aborted_message, var.message) + type = "query alert" + + query = < ${var.mysql_aborted_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.mysql_aborted_threshold_warning + critical = var.mysql_aborted_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mysql", "resource:mysql", "team:claranet", "created-by:terraform"], var.mysql_aborted_extra_tags) +} + +resource "datadog_monitor" "mysql_slow" { + count = var.mysql_slow_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql Slow queries {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.mysql_slow_message, var.message) + type = "query alert" + + query = < ${var.mysql_slow_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.mysql_slow_threshold_warning + critical = var.mysql_slow_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mysql", "resource:mysql", "team:claranet", "created-by:terraform"], var.mysql_slow_extra_tags) +} + +resource "datadog_monitor" "mysql_pool_efficiency" { + count = var.mysql_pool_efficiency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql Innodb buffer pool efficiency {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.mysql_pool_efficiency_message, var.message) + type = "query alert" + + query = < ${var.mysql_pool_efficiency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.mysql_pool_efficiency_threshold_warning + critical = var.mysql_pool_efficiency_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mysql", "resource:mysql", "team:claranet", "created-by:terraform"], var.mysql_pool_efficiency_extra_tags) +} + +resource "datadog_monitor" "mysql_pool_utilization" { + count = var.mysql_pool_utilization_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql Innodb buffer pool utilization {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.mysql_pool_utilization_message, var.message) + type = "query alert" + + query = < ${var.mysql_pool_utilization_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.mysql_pool_utilization_threshold_warning + critical = var.mysql_pool_utilization_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mysql", "resource:mysql", "team:claranet", "created-by:terraform"], var.mysql_pool_utilization_extra_tags) +} + +resource "datadog_monitor" "mysql_threads_anomaly" { + count = var.mysql_threads_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql threads changed abnormally" + message = coalesce(var.mysql_threads_message, var.message) + type = "metric alert" + + query = <= ${var.mysql_threads_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.mysql_threads_threshold_critical + critical_recovery = 0 + } + + monitor_threshold_windows { + trigger_window = var.mysql_threads_alert_window + recovery_window = var.mysql_threads_alert_window + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mysql", "resource:mysql", "team:claranet", "created-by:terraform"], var.mysql_threads_extra_tags) +} + +resource "datadog_monitor" "mysql_questions_anomaly" { + count = var.mysql_questions_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql queries changed abnormally" + message = coalesce(var.mysql_questions_message, var.message) + type = "metric alert" + + query = <= ${var.mysql_questions_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.mysql_questions_threshold_critical + critical_recovery = 0 + } + + monitor_threshold_windows { + trigger_window = var.mysql_questions_alert_window + recovery_window = var.mysql_questions_alert_window + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mysql", "resource:mysql", "team:claranet", "created-by:terraform"], var.mysql_questions_extra_tags) +} + +resource "datadog_monitor" "mysql_replication_lag" { + count = var.mysql_replication_lag_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql replication lag {{#is_alert}}{{{comparator}}} {{threshold}}s ({{value}}s){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}s ({{value}}s){{/is_warning}}" + message = coalesce(var.mysql_replication_lag_message, var.message) + type = "query alert" + + query = < ${var.mysql_replication_lag_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.mysql_replication_lag_threshold_warning + critical = var.mysql_replication_lag_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = false + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:mysql", "resource:mysql", "team:claranet", "created-by:terraform"], var.mysql_replication_lag_extra_tags) +} + +resource "datadog_monitor" "mysql_replication_status" { + count = var.mysql_replication_status_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Mysql replication status changed abnormally" + message = coalesce(var.mysql_replication_status_message, var.message) + type = "metric alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.postgresql_availability](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.postgresql_connection_too_high](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.postgresql_too_many_locks](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the metric evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [postgresql\_availability\_enabled](#input\_postgresql\_availability\_enabled) | Flag to enable PostgreSQL availability monitor | `string` | `"true"` | no | +| [postgresql\_availability\_extra\_tags](#input\_postgresql\_availability\_extra\_tags) | Extra tags for PostgreSQL availability monitor | `list(string)` | `[]` | no | +| [postgresql\_availability\_message](#input\_postgresql\_availability\_message) | Custom message for PostgreSQL availability monitor | `string` | `""` | no | +| [postgresql\_availability\_no\_data\_timeframe](#input\_postgresql\_availability\_no\_data\_timeframe) | PostgreSQL availability monitor no data timeframe | `string` | `10` | no | +| [postgresql\_availability\_threshold\_warning](#input\_postgresql\_availability\_threshold\_warning) | PostgreSQL availability monitor (warning threshold) | `string` | `3` | no | +| [postgresql\_connection\_enabled](#input\_postgresql\_connection\_enabled) | Flag to enable PostgreSQL connection monitor | `string` | `"true"` | no | +| [postgresql\_connection\_extra\_tags](#input\_postgresql\_connection\_extra\_tags) | Extra tags for PostgreSQL connection connects monitor | `list(string)` | `[]` | no | +| [postgresql\_connection\_message](#input\_postgresql\_connection\_message) | Custom message for PostgreSQL connection monitor | `string` | `""` | no | +| [postgresql\_connection\_threshold\_critical](#input\_postgresql\_connection\_threshold\_critical) | Maximum critical acceptable percent of connections | `number` | `80` | no | +| [postgresql\_connection\_threshold\_warning](#input\_postgresql\_connection\_threshold\_warning) | Maximum warning acceptable percent of connections | `number` | `70` | no | +| [postgresql\_connection\_time\_aggregator](#input\_postgresql\_connection\_time\_aggregator) | Monitor time aggregator for PostgreSQL connection monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [postgresql\_connection\_timeframe](#input\_postgresql\_connection\_timeframe) | Monitor timeframe for PostgreSQL connection monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [postgresql\_lock\_enabled](#input\_postgresql\_lock\_enabled) | Flag to enable PostgreSQL lock monitor | `string` | `"true"` | no | +| [postgresql\_lock\_extra\_tags](#input\_postgresql\_lock\_extra\_tags) | Extra tags for PostgreSQL lock connects monitor | `list(string)` | `[]` | no | +| [postgresql\_lock\_message](#input\_postgresql\_lock\_message) | Custom message for PostgreSQL lock monitor | `string` | `""` | no | +| [postgresql\_lock\_threshold\_critical](#input\_postgresql\_lock\_threshold\_critical) | Maximum critical acceptable number of locks | `number` | `99` | no | +| [postgresql\_lock\_threshold\_warning](#input\_postgresql\_lock\_threshold\_warning) | Maximum warning acceptable number of locks | `number` | `70` | no | +| [postgresql\_lock\_time\_aggregator](#input\_postgresql\_lock\_time\_aggregator) | Monitor time aggregator for PostgreSQL lock monitor [available values: min, max or avg] | `string` | `"min"` | no | +| [postgresql\_lock\_timeframe](#input\_postgresql\_lock\_timeframe) | Monitor timeframe for PostgreSQL lock monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [postgresql\_availability\_id](#output\_postgresql\_availability\_id) | id for monitor postgresql\_availability | +| [postgresql\_connection\_too\_high\_id](#output\_postgresql\_connection\_too\_high\_id) | id for monitor postgresql\_connection\_too\_high | +| [postgresql\_too\_many\_locks\_id](#output\_postgresql\_too\_many\_locks\_id) | id for monitor postgresql\_too\_many\_locks | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/postgres/](https://docs.datadoghq.com/integrations/postgres/) diff --git a/.terraform/modules/datadog-monitors-system-generic/database/postgresql/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/database/postgresql/inputs.tf new file mode 100755 index 0000000..1030a74 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/postgresql/inputs.tf @@ -0,0 +1,168 @@ +variable "environment" { + description = "Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds for the metric evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# PostgreSQL specific +################################## +### PostgreSQL availability ### +################################## + +variable "postgresql_availability_enabled" { + description = "Flag to enable PostgreSQL availability monitor" + type = string + default = "true" +} + +variable "postgresql_availability_extra_tags" { + description = "Extra tags for PostgreSQL availability monitor" + type = list(string) + default = [] +} + +variable "postgresql_availability_message" { + description = "Custom message for PostgreSQL availability monitor" + type = string + default = "" +} + +variable "postgresql_availability_threshold_warning" { + description = "PostgreSQL availability monitor (warning threshold)" + type = string + default = 3 +} + +variable "postgresql_availability_no_data_timeframe" { + description = "PostgreSQL availability monitor no data timeframe" + type = string + default = 10 +} + +################################## +### PostgreSQL connections ### +################################## + +variable "postgresql_connection_threshold_critical" { + default = 80 + description = "Maximum critical acceptable percent of connections" +} + +variable "postgresql_connection_threshold_warning" { + default = 70 + description = "Maximum warning acceptable percent of connections" +} + +variable "postgresql_connection_enabled" { + description = "Flag to enable PostgreSQL connection monitor" + type = string + default = "true" +} + +variable "postgresql_connection_extra_tags" { + description = "Extra tags for PostgreSQL connection connects monitor" + type = list(string) + default = [] +} + +variable "postgresql_connection_message" { + description = "Custom message for PostgreSQL connection monitor" + type = string + default = "" +} + +variable "postgresql_connection_time_aggregator" { + description = "Monitor time aggregator for PostgreSQL connection monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "postgresql_connection_timeframe" { + description = "Monitor timeframe for PostgreSQL connection monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +############################ +### PostgreSQL locks ### +############################ + +variable "postgresql_lock_threshold_critical" { + default = 99 + description = "Maximum critical acceptable number of locks" +} + +variable "postgresql_lock_threshold_warning" { + default = 70 + description = "Maximum warning acceptable number of locks" +} + +variable "postgresql_lock_enabled" { + description = "Flag to enable PostgreSQL lock monitor" + type = string + default = "true" +} + +variable "postgresql_lock_extra_tags" { + description = "Extra tags for PostgreSQL lock connects monitor" + type = list(string) + default = [] +} + +variable "postgresql_lock_message" { + description = "Custom message for PostgreSQL lock monitor" + type = string + default = "" +} + +variable "postgresql_lock_time_aggregator" { + description = "Monitor time aggregator for PostgreSQL lock monitor [available values: min, max or avg]" + type = string + default = "min" +} + +variable "postgresql_lock_timeframe" { + description = "Monitor timeframe for PostgreSQL lock monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/database/postgresql/modules.tf b/.terraform/modules/datadog-monitors-system-generic/database/postgresql/modules.tf new file mode 100755 index 0000000..4004ab7 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/postgresql/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "postgres" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/database/postgresql/monitors-postgresql.tf b/.terraform/modules/datadog-monitors-system-generic/database/postgresql/monitors-postgresql.tf new file mode 100755 index 0000000..ce03d16 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/postgresql/monitors-postgresql.tf @@ -0,0 +1,84 @@ +resource "datadog_monitor" "postgresql_availability" { + count = var.postgresql_availability_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] PostgreSQL server does not respond" + message = coalesce(var.postgresql_availability_message, var.message) + type = "service check" + + query = < ${var.postgresql_connection_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.postgresql_connection_threshold_warning + critical = var.postgresql_connection_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:postgres", "resource:postgresql", "team:claranet", "created-by:terraform"], var.postgresql_connection_extra_tags) +} + +resource "datadog_monitor" "postgresql_too_many_locks" { + count = var.postgresql_lock_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] PostgreSQL too many locks {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.postgresql_lock_message, var.message) + type = "query alert" + + query = < ${var.postgresql_lock_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.postgresql_lock_threshold_warning + critical = var.postgresql_lock_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:postgres", "resource:postgresql", "team:claranet", "created-by:terraform"], var.postgresql_lock_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/database/postgresql/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/database/postgresql/outputs.tf new file mode 100755 index 0000000..bb81f0b --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/postgresql/outputs.tf @@ -0,0 +1,15 @@ +output "postgresql_availability_id" { + description = "id for monitor postgresql_availability" + value = datadog_monitor.postgresql_availability.*.id +} + +output "postgresql_connection_too_high_id" { + description = "id for monitor postgresql_connection_too_high" + value = datadog_monitor.postgresql_connection_too_high.*.id +} + +output "postgresql_too_many_locks_id" { + description = "id for monitor postgresql_too_many_locks" + value = datadog_monitor.postgresql_too_many_locks.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/database/postgresql/versions.tf b/.terraform/modules/datadog-monitors-system-generic/database/postgresql/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/postgresql/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/database/proxysql/README.md b/.terraform/modules/datadog-monitors-system-generic/database/proxysql/README.md new file mode 100755 index 0000000..9becd38 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/proxysql/README.md @@ -0,0 +1,116 @@ +# DATABASE PROXYSQL DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-database-proxysql" { + source = "claranet/monitors/datadog//database/proxysql" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- ProxySQL Client connections aborted +- ProxySQL Pool connections failure +- ProxySQL Server connections aborted +- ProxySQL Slow queries +- ProxySQL Thread Worker + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.proxysql_client_conn_aborted](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.proxysql_pool_conn_failure](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.proxysql_server_conn_aborted](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.proxysql_slow](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.proxysql_thread_worker](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the metric evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `false` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [proxysql\_client\_conn\_aborted\_enabled](#input\_proxysql\_client\_conn\_aborted\_enabled) | Flag to enable ProxySQL client connections aborted monitor | `string` | `"true"` | no | +| [proxysql\_client\_conn\_aborted\_extra\_tags](#input\_proxysql\_client\_conn\_aborted\_extra\_tags) | Extra tags for ProxySQL client connections aborted monitor | `list(string)` | `[]` | no | +| [proxysql\_client\_conn\_aborted\_message](#input\_proxysql\_client\_conn\_aborted\_message) | Custom message for ProxySQL client connections aborted monitor | `string` | `""` | no | +| [proxysql\_client\_conn\_aborted\_threshold\_critical](#input\_proxysql\_client\_conn\_aborted\_threshold\_critical) | Maximum critical acceptable percent of aborted connects | `number` | `10` | no | +| [proxysql\_client\_conn\_aborted\_threshold\_warning](#input\_proxysql\_client\_conn\_aborted\_threshold\_warning) | Maximum warning acceptable percent of aborted connects | `number` | `1` | no | +| [proxysql\_client\_conn\_aborted\_time\_aggregator](#input\_proxysql\_client\_conn\_aborted\_time\_aggregator) | Monitor time aggregator for ProxySQL client connections aborted monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [proxysql\_client\_conn\_aborted\_timeframe](#input\_proxysql\_client\_conn\_aborted\_timeframe) | Monitor timeframe for ProxySQL client connections aborted monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_10m"` | no | +| [proxysql\_pool\_conn\_failure\_enabled](#input\_proxysql\_pool\_conn\_failure\_enabled) | Flag to enable ProxySQL pool connections failure monitor | `string` | `"true"` | no | +| [proxysql\_pool\_conn\_failure\_extra\_tags](#input\_proxysql\_pool\_conn\_failure\_extra\_tags) | Extra tags for ProxySQL pool connections failure monitor | `list(string)` | `[]` | no | +| [proxysql\_pool\_conn\_failure\_message](#input\_proxysql\_pool\_conn\_failure\_message) | Custom message for ProxySQL pool connections failure monitor | `string` | `""` | no | +| [proxysql\_pool\_conn\_failure\_threshold\_critical](#input\_proxysql\_pool\_conn\_failure\_threshold\_critical) | Maximum critical acceptable of pool connections failure | `number` | `20` | no | +| [proxysql\_pool\_conn\_failure\_threshold\_warning](#input\_proxysql\_pool\_conn\_failure\_threshold\_warning) | Maximum warning acceptable of pool connections failure | `number` | `1` | no | +| [proxysql\_pool\_conn\_failure\_time\_aggregator](#input\_proxysql\_pool\_conn\_failure\_time\_aggregator) | Monitor time aggregator for ProxySQL pool connections failure monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [proxysql\_pool\_conn\_failure\_timeframe](#input\_proxysql\_pool\_conn\_failure\_timeframe) | Monitor timeframe for ProxySQL pool connections failure monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [proxysql\_server\_conn\_aborted\_enabled](#input\_proxysql\_server\_conn\_aborted\_enabled) | Flag to enable ProxySQL server connections aborted monitor | `string` | `"true"` | no | +| [proxysql\_server\_conn\_aborted\_extra\_tags](#input\_proxysql\_server\_conn\_aborted\_extra\_tags) | Extra tags for ProxySQL server connections aborted monitor | `list(string)` | `[]` | no | +| [proxysql\_server\_conn\_aborted\_message](#input\_proxysql\_server\_conn\_aborted\_message) | Custom message for ProxySQL server connections aborted monitor | `string` | `""` | no | +| [proxysql\_server\_conn\_aborted\_threshold\_critical](#input\_proxysql\_server\_conn\_aborted\_threshold\_critical) | Maximum critical acceptable percent of aborted connects | `number` | `10` | no | +| [proxysql\_server\_conn\_aborted\_threshold\_warning](#input\_proxysql\_server\_conn\_aborted\_threshold\_warning) | Maximum warning acceptable percent of aborted connects | `number` | `1` | no | +| [proxysql\_server\_conn\_aborted\_time\_aggregator](#input\_proxysql\_server\_conn\_aborted\_time\_aggregator) | Monitor time aggregator for ProxySQL server connections aborted monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [proxysql\_server\_conn\_aborted\_timeframe](#input\_proxysql\_server\_conn\_aborted\_timeframe) | Monitor timeframe for ProxySQL server connections aborted monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_10m"` | no | +| [proxysql\_slow\_enabled](#input\_proxysql\_slow\_enabled) | Flag to enable ProxySQL slow queries monitor | `string` | `"true"` | no | +| [proxysql\_slow\_extra\_tags](#input\_proxysql\_slow\_extra\_tags) | Extra tags for ProxySQL slow queries monitor | `list(string)` | `[]` | no | +| [proxysql\_slow\_message](#input\_proxysql\_slow\_message) | Custom message for ProxySQL slow queries monitor | `string` | `""` | no | +| [proxysql\_slow\_threshold\_critical](#input\_proxysql\_slow\_threshold\_critical) | Maximum critical acceptable of slow queries | `number` | `20` | no | +| [proxysql\_slow\_threshold\_warning](#input\_proxysql\_slow\_threshold\_warning) | Maximum warning acceptable of slow queries | `number` | `1` | no | +| [proxysql\_slow\_time\_aggregator](#input\_proxysql\_slow\_time\_aggregator) | Monitor time aggregator for ProxySQL slow queries monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [proxysql\_slow\_timeframe](#input\_proxysql\_slow\_timeframe) | Monitor timeframe for ProxySQL slow queries monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [proxysql\_thread\_worker\_enabled](#input\_proxysql\_thread\_worker\_enabled) | Flag to enable ProxySQL thread worker monitor | `string` | `"true"` | no | +| [proxysql\_thread\_worker\_extra\_tags](#input\_proxysql\_thread\_worker\_extra\_tags) | Extra tags for ProxySQL thread worker monitor | `list(string)` | `[]` | no | +| [proxysql\_thread\_worker\_message](#input\_proxysql\_thread\_worker\_message) | Custom message for ProxySQL thread worker monitor | `string` | `""` | no | +| [proxysql\_thread\_worker\_threshold\_critical](#input\_proxysql\_thread\_worker\_threshold\_critical) | Minimum critical acceptable of thread worker running | `number` | `1` | no | +| [proxysql\_thread\_worker\_threshold\_warning](#input\_proxysql\_thread\_worker\_threshold\_warning) | Minimum warning acceptable of thread worker running | `number` | `4` | no | +| [proxysql\_thread\_worker\_time\_aggregator](#input\_proxysql\_thread\_worker\_time\_aggregator) | Monitor time aggregator for ProxySQL thread worker monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [proxysql\_thread\_worker\_timeframe](#input\_proxysql\_thread\_worker\_timeframe) | Monitor timeframe for ProxySQL thread worker monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [proxysql\_client\_conn\_aborted\_id](#output\_proxysql\_client\_conn\_aborted\_id) | id for monitor proxysql\_client\_conn\_aborted | +| [proxysql\_pool\_conn\_failure\_id](#output\_proxysql\_pool\_conn\_failure\_id) | id for monitor proxysql\_pool\_conn\_failure | +| [proxysql\_server\_conn\_aborted\_id](#output\_proxysql\_server\_conn\_aborted\_id) | id for monitor proxysql\_server\_conn\_aborted | +| [proxysql\_slow\_id](#output\_proxysql\_slow\_id) | id for monitor proxysql\_slow | +| [proxysql\_thread\_worker\_id](#output\_proxysql\_thread\_worker\_id) | id for monitor proxysql\_thread\_worker | +## Related documentation + +* [Datadog documentation](https://docs.datadoghq.com/integrations/proxysql/) +* [ProxySQL documentation](https://proxysql.com/documentation/) diff --git a/.terraform/modules/datadog-monitors-system-generic/database/proxysql/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/database/proxysql/inputs.tf new file mode 100755 index 0000000..7314488 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/proxysql/inputs.tf @@ -0,0 +1,266 @@ +variable "environment" { + description = "Environment" + type = string +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds for the metric evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = false +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# ProxySQL specific + +################################## +### ProxySQL thread worker ### +################################## + +variable "proxysql_thread_worker_enabled" { + description = "Flag to enable ProxySQL thread worker monitor" + type = string + default = "true" +} + +variable "proxysql_thread_worker_extra_tags" { + description = "Extra tags for ProxySQL thread worker monitor" + type = list(string) + default = [] +} + +variable "proxysql_thread_worker_message" { + description = "Custom message for ProxySQL thread worker monitor" + type = string + default = "" +} + +variable "proxysql_thread_worker_threshold_critical" { + description = "Minimum critical acceptable of thread worker running" + default = 1 +} + +variable "proxysql_thread_worker_threshold_warning" { + description = "Minimum warning acceptable of thread worker running" + default = 4 +} + +variable "proxysql_thread_worker_time_aggregator" { + description = "Monitor time aggregator for ProxySQL thread worker monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "proxysql_thread_worker_timeframe" { + description = "Monitor timeframe for ProxySQL thread worker monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +################################# +### ProxySQL slow queries ### +################################# + +variable "proxysql_slow_enabled" { + description = "Flag to enable ProxySQL slow queries monitor" + type = string + default = "true" +} + +variable "proxysql_slow_extra_tags" { + description = "Extra tags for ProxySQL slow queries monitor" + type = list(string) + default = [] +} + +variable "proxysql_slow_message" { + description = "Custom message for ProxySQL slow queries monitor" + type = string + default = "" +} + +variable "proxysql_slow_threshold_critical" { + description = "Maximum critical acceptable of slow queries" + default = 20 +} + +variable "proxysql_slow_threshold_warning" { + description = "Maximum warning acceptable of slow queries" + default = 1 +} + +variable "proxysql_slow_time_aggregator" { + description = "Monitor time aggregator for ProxySQL slow queries monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "proxysql_slow_timeframe" { + description = "Monitor timeframe for ProxySQL slow queries monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +########################################## +### ProxySQL Client aborted connects ### +########################################## + +variable "proxysql_client_conn_aborted_enabled" { + description = "Flag to enable ProxySQL client connections aborted monitor" + type = string + default = "true" +} + +variable "proxysql_client_conn_aborted_extra_tags" { + description = "Extra tags for ProxySQL client connections aborted monitor" + type = list(string) + default = [] +} + +variable "proxysql_client_conn_aborted_message" { + description = "Custom message for ProxySQL client connections aborted monitor" + type = string + default = "" +} + +variable "proxysql_client_conn_aborted_threshold_critical" { + description = "Maximum critical acceptable percent of aborted connects" + default = 10 +} + +variable "proxysql_client_conn_aborted_threshold_warning" { + description = "Maximum warning acceptable percent of aborted connects" + default = 1 +} + +variable "proxysql_client_conn_aborted_time_aggregator" { + description = "Monitor time aggregator for ProxySQL client connections aborted monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "proxysql_client_conn_aborted_timeframe" { + description = "Monitor timeframe for ProxySQL client connections aborted monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_10m" +} + +########################################## +### ProxySQL Server aborted connects ### +########################################## + +variable "proxysql_server_conn_aborted_enabled" { + description = "Flag to enable ProxySQL server connections aborted monitor" + type = string + default = "true" +} + +variable "proxysql_server_conn_aborted_extra_tags" { + description = "Extra tags for ProxySQL server connections aborted monitor" + type = list(string) + default = [] +} + +variable "proxysql_server_conn_aborted_message" { + description = "Custom message for ProxySQL server connections aborted monitor" + type = string + default = "" +} + +variable "proxysql_server_conn_aborted_threshold_critical" { + description = "Maximum critical acceptable percent of aborted connects" + default = 10 +} + +variable "proxysql_server_conn_aborted_threshold_warning" { + description = "Maximum warning acceptable percent of aborted connects" + default = 1 +} + +variable "proxysql_server_conn_aborted_time_aggregator" { + description = "Monitor time aggregator for ProxySQL server connections aborted monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "proxysql_server_conn_aborted_timeframe" { + description = "Monitor timeframe for ProxySQL server connections aborted monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_10m" +} + + +########################################## +### ProxySQL Pool Connection Failure ### +########################################## + +variable "proxysql_pool_conn_failure_enabled" { + description = "Flag to enable ProxySQL pool connections failure monitor" + type = string + default = "true" +} + +variable "proxysql_pool_conn_failure_extra_tags" { + description = "Extra tags for ProxySQL pool connections failure monitor" + type = list(string) + default = [] +} + +variable "proxysql_pool_conn_failure_message" { + description = "Custom message for ProxySQL pool connections failure monitor" + type = string + default = "" +} + +variable "proxysql_pool_conn_failure_threshold_critical" { + description = "Maximum critical acceptable of pool connections failure" + default = 20 +} + +variable "proxysql_pool_conn_failure_threshold_warning" { + description = "Maximum warning acceptable of pool connections failure" + default = 1 +} + +variable "proxysql_pool_conn_failure_time_aggregator" { + description = "Monitor time aggregator for ProxySQL pool connections failure monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "proxysql_pool_conn_failure_timeframe" { + description = "Monitor timeframe for ProxySQL pool connections failure monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/database/proxysql/modules.tf b/.terraform/modules/datadog-monitors-system-generic/database/proxysql/modules.tf new file mode 100755 index 0000000..ac04d58 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/proxysql/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "proxysql" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/database/proxysql/monitors-proxysql.tf b/.terraform/modules/datadog-monitors-system-generic/database/proxysql/monitors-proxysql.tf new file mode 100755 index 0000000..471721d --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/proxysql/monitors-proxysql.tf @@ -0,0 +1,134 @@ +resource "datadog_monitor" "proxysql_thread_worker" { + count = var.proxysql_thread_worker_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ProxySQL Thread Worker {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.proxysql_thread_worker_message, var.message) + type = "query alert" + + query = < ${var.proxysql_slow_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.proxysql_slow_threshold_warning + critical = var.proxysql_slow_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:proxysql", "resource:proxysql", "team:claranet", "created-by:terraform"], var.proxysql_slow_extra_tags) +} + +resource "datadog_monitor" "proxysql_client_conn_aborted" { + count = var.proxysql_client_conn_aborted_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ProxySQL Client connections aborted {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.proxysql_client_conn_aborted_message, var.message) + type = "query alert" + + query = < ${var.proxysql_client_conn_aborted_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.proxysql_client_conn_aborted_threshold_warning + critical = var.proxysql_client_conn_aborted_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:proxysql", "resource:proxysql", "team:claranet", "created-by:terraform"], var.proxysql_client_conn_aborted_extra_tags) +} + +resource "datadog_monitor" "proxysql_server_conn_aborted" { + count = var.proxysql_server_conn_aborted_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ProxySQL Server connections aborted {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.proxysql_server_conn_aborted_message, var.message) + type = "query alert" + + query = < ${var.proxysql_server_conn_aborted_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.proxysql_server_conn_aborted_threshold_warning + critical = var.proxysql_server_conn_aborted_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:proxysql", "resource:proxysql", "team:claranet", "created-by:terraform"], var.proxysql_server_conn_aborted_extra_tags) +} + +resource "datadog_monitor" "proxysql_pool_conn_failure" { + count = var.proxysql_pool_conn_failure_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] ProxySQL Pool connections failure {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.proxysql_pool_conn_failure_message, var.message) + type = "query alert" + + query = < ${var.proxysql_pool_conn_failure_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.proxysql_pool_conn_failure_threshold_warning + critical = var.proxysql_pool_conn_failure_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + require_full_window = true + timeout_h = 0 + include_tags = true + + tags = concat(["env:${var.environment}", "type:database", "provider:proxysql", "resource:proxysql", "team:claranet", "created-by:terraform"], var.proxysql_pool_conn_failure_extra_tags) +} diff --git a/.terraform/modules/datadog-monitors-system-generic/database/proxysql/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/database/proxysql/outputs.tf new file mode 100755 index 0000000..665c7d3 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/proxysql/outputs.tf @@ -0,0 +1,25 @@ +output "proxysql_client_conn_aborted_id" { + description = "id for monitor proxysql_client_conn_aborted" + value = datadog_monitor.proxysql_client_conn_aborted.*.id +} + +output "proxysql_pool_conn_failure_id" { + description = "id for monitor proxysql_pool_conn_failure" + value = datadog_monitor.proxysql_pool_conn_failure.*.id +} + +output "proxysql_server_conn_aborted_id" { + description = "id for monitor proxysql_server_conn_aborted" + value = datadog_monitor.proxysql_server_conn_aborted.*.id +} + +output "proxysql_slow_id" { + description = "id for monitor proxysql_slow" + value = datadog_monitor.proxysql_slow.*.id +} + +output "proxysql_thread_worker_id" { + description = "id for monitor proxysql_thread_worker" + value = datadog_monitor.proxysql_thread_worker.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/database/proxysql/versions.tf b/.terraform/modules/datadog-monitors-system-generic/database/proxysql/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/proxysql/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/database/redis/README.md b/.terraform/modules/datadog-monitors-system-generic/database/redis/README.md new file mode 100755 index 0000000..c81e648 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/redis/README.md @@ -0,0 +1,165 @@ +# DATABASE REDIS DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-database-redis" { + source = "claranet/monitors/datadog//database/redis" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Redis blocked clients +- Redis does not respond +- Redis evicted keys +- Redis expired keys +- Redis hitrate +- Redis keyspace seems full (no changes since ${var.keyspace_timeframe}) +- Redis latency +- Redis memory fragmented +- Redis memory used +- Redis rejected connections + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.blocked_clients](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.evicted_keys](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.expirations](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.hitrate](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.keyspace_full](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.memory_frag](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.memory_used](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.not_responding](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.rejected_connections](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [blocked\_clients\_enabled](#input\_blocked\_clients\_enabled) | Flag to enable Redis Blocked clients monitor | `string` | `"true"` | no | +| [blocked\_clients\_extra\_tags](#input\_blocked\_clients\_extra\_tags) | Extra tags for Redis Blocked clients monitor | `list(string)` | `[]` | no | +| [blocked\_clients\_message](#input\_blocked\_clients\_message) | Custom message for Redis Blocked clients monitor | `string` | `""` | no | +| [blocked\_clients\_threshold\_critical](#input\_blocked\_clients\_threshold\_critical) | Blocked clients rate (critical threshold) | `number` | `30` | no | +| [blocked\_clients\_threshold\_warning](#input\_blocked\_clients\_threshold\_warning) | Blocked clients rate (warning threshold) | `number` | `10` | no | +| [blocked\_clients\_time\_aggregator](#input\_blocked\_clients\_time\_aggregator) | Monitor aggregator for Redis Blocked clients [available values: min, max or avg] | `string` | `"min"` | no | +| [blocked\_clients\_timeframe](#input\_blocked\_clients\_timeframe) | Monitor timeframe for Redis Blocked clients [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [evictedkeys\_change\_enabled](#input\_evictedkeys\_change\_enabled) | Flag to enable Redis evicted keys monitor | `string` | `"true"` | no | +| [evictedkeys\_change\_extra\_tags](#input\_evictedkeys\_change\_extra\_tags) | Extra tags for Redis evicted keys monitor | `list(string)` | `[]` | no | +| [evictedkeys\_change\_message](#input\_evictedkeys\_change\_message) | Custom message for Redis evicted keys monitor | `string` | `""` | no | +| [evictedkeys\_change\_threshold\_critical](#input\_evictedkeys\_change\_threshold\_critical) | Evicted keys change (critical threshold) | `number` | `100` | no | +| [evictedkeys\_change\_threshold\_warning](#input\_evictedkeys\_change\_threshold\_warning) | Evicted keys change (warning threshold) | `number` | `20` | no | +| [evictedkeys\_change\_time\_aggregator](#input\_evictedkeys\_change\_time\_aggregator) | Monitor aggregator for Redis evicted keys [available values: min, max or avg] | `string` | `"avg"` | no | +| [evictedkeys\_change\_timeframe](#input\_evictedkeys\_change\_timeframe) | Monitor timeframe for Redis evicted keys [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [expirations\_rate\_enabled](#input\_expirations\_rate\_enabled) | Flag to enable Redis keys expirations monitor | `string` | `"true"` | no | +| [expirations\_rate\_extra\_tags](#input\_expirations\_rate\_extra\_tags) | Extra tags for Redis keys expirations monitor | `list(string)` | `[]` | no | +| [expirations\_rate\_message](#input\_expirations\_rate\_message) | Custom message for Redis keys expirations monitor | `string` | `""` | no | +| [expirations\_rate\_threshold\_critical](#input\_expirations\_rate\_threshold\_critical) | Expirations percent (critical threshold) | `number` | `80` | no | +| [expirations\_rate\_threshold\_warning](#input\_expirations\_rate\_threshold\_warning) | Expirations percent (warning threshold) | `number` | `60` | no | +| [expirations\_rate\_time\_aggregator](#input\_expirations\_rate\_time\_aggregator) | Monitor aggregator for Redis keys expirations [available values: min, max or avg] | `string` | `"min"` | no | +| [expirations\_rate\_timeframe](#input\_expirations\_rate\_timeframe) | Monitor timeframe for Redis keys expirations [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [hitrate\_enabled](#input\_hitrate\_enabled) | Flag to enable Redis hitrate monitor | `string` | `"true"` | no | +| [hitrate\_extra\_tags](#input\_hitrate\_extra\_tags) | Extra tags for Redis hitrate monitor | `list(string)` | `[]` | no | +| [hitrate\_message](#input\_hitrate\_message) | Custom message for Redis hitrate monitor | `string` | `""` | no | +| [hitrate\_threshold\_critical](#input\_hitrate\_threshold\_critical) | hitrate limit (critical threshold) | `number` | `10` | no | +| [hitrate\_threshold\_warning](#input\_hitrate\_threshold\_warning) | hitrate limit (warning threshold) | `number` | `30` | no | +| [hitrate\_time\_aggregator](#input\_hitrate\_time\_aggregator) | Monitor aggregator for Redis hitrate [available values: min, max or avg] | `string` | `"max"` | no | +| [hitrate\_timeframe](#input\_hitrate\_timeframe) | Monitor timeframe for Redis hitrate [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [keyspace\_enabled](#input\_keyspace\_enabled) | Flag to enable Redis keyspace monitor | `string` | `"true"` | no | +| [keyspace\_extra\_tags](#input\_keyspace\_extra\_tags) | Extra tags for Redis keyspace monitor | `list(string)` | `[]` | no | +| [keyspace\_message](#input\_keyspace\_message) | Custom message for Redis keyspace monitor | `string` | `""` | no | +| [keyspace\_threshold\_critical](#input\_keyspace\_threshold\_critical) | Keyspace no changement (critical threshold) | `number` | `0` | no | +| [keyspace\_threshold\_warning](#input\_keyspace\_threshold\_warning) | Keyspace no changement (warning threshold) | `number` | `1` | no | +| [keyspace\_time\_aggregator](#input\_keyspace\_time\_aggregator) | Monitor aggregator for Redis keyspace [available values: min, max or avg] | `string` | `"min"` | no | +| [keyspace\_timeframe](#input\_keyspace\_timeframe) | Monitor timeframe for Redis keyspace [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [latency\_enabled](#input\_latency\_enabled) | Flag to enable Redis latency monitor | `string` | `"true"` | no | +| [latency\_extra\_tags](#input\_latency\_extra\_tags) | Extra tags for Redis latency monitor | `list(string)` | `[]` | no | +| [latency\_message](#input\_latency\_message) | Custom message for Redis latency monitor | `string` | `""` | no | +| [latency\_threshold\_critical](#input\_latency\_threshold\_critical) | latency limit (critical threshold) | `number` | `100` | no | +| [latency\_threshold\_warning](#input\_latency\_threshold\_warning) | latency limit (warning threshold) | `number` | `50` | no | +| [latency\_time\_aggregator](#input\_latency\_time\_aggregator) | Monitor aggregator for Redis latency [available values: min, max or avg] | `string` | `"min"` | no | +| [latency\_timeframe](#input\_latency\_timeframe) | Monitor timeframe for Redis latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [mem\_frag\_enabled](#input\_mem\_frag\_enabled) | Flag to enable Redis memory RAM fragmentation monitor | `string` | `"true"` | no | +| [mem\_frag\_extra\_tags](#input\_mem\_frag\_extra\_tags) | Extra tags for Redis memory RAM fragmentation monitor | `list(string)` | `[]` | no | +| [mem\_frag\_message](#input\_mem\_frag\_message) | Custom message for Redis memory RAM fragmentation monitor | `string` | `""` | no | +| [mem\_frag\_threshold\_critical](#input\_mem\_frag\_threshold\_critical) | memory RAM fragmentation limit (critical threshold) | `number` | `150` | no | +| [mem\_frag\_threshold\_warning](#input\_mem\_frag\_threshold\_warning) | memory RAM fragmentation limit (warning threshold) | `number` | `130` | no | +| [mem\_frag\_time\_aggregator](#input\_mem\_frag\_time\_aggregator) | Monitor aggregator for Redis memory RAM fragmentation [available values: min, max or avg] | `string` | `"min"` | no | +| [mem\_frag\_timeframe](#input\_mem\_frag\_timeframe) | Monitor timeframe for Redis memory RAM fragmentation [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [mem\_used\_enabled](#input\_mem\_used\_enabled) | Flag to enable Redis RAM memory used monitor | `string` | `"true"` | no | +| [mem\_used\_extra\_tags](#input\_mem\_used\_extra\_tags) | Extra tags for Redis RAM memory used monitor | `list(string)` | `[]` | no | +| [mem\_used\_message](#input\_mem\_used\_message) | Custom message for Redis RAM memory used monitor | `string` | `""` | no | +| [mem\_used\_threshold\_critical](#input\_mem\_used\_threshold\_critical) | RAM memory used limit (critical threshold) | `number` | `95` | no | +| [mem\_used\_threshold\_warning](#input\_mem\_used\_threshold\_warning) | RAM memory used limit (warning threshold) | `number` | `85` | no | +| [mem\_used\_time\_aggregator](#input\_mem\_used\_time\_aggregator) | Monitor aggregator for Redis RAM memory used [available values: min, max or avg] | `string` | `"min"` | no | +| [mem\_used\_timeframe](#input\_mem\_used\_timeframe) | Monitor timeframe for Redis RAM memory used [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when a Redis monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the metric evaluation | `number` | `300` | no | +| [not\_responding\_enabled](#input\_not\_responding\_enabled) | Flag to enable Redis does not respond monitor | `string` | `"true"` | no | +| [not\_responding\_extra\_tags](#input\_not\_responding\_extra\_tags) | Extra tags for Redis does not respond monitor | `list(string)` | `[]` | no | +| [not\_responding\_message](#input\_not\_responding\_message) | Custom message for Redis does not respond monitor | `string` | `""` | no | +| [not\_responding\_no\_data\_timeframe](#input\_not\_responding\_no\_data\_timeframe) | Redis does not respond monitor no data timeframe | `string` | `10` | no | +| [not\_responding\_threshold\_warning](#input\_not\_responding\_threshold\_warning) | Redis does not respond monitor (warning threshold) | `string` | `3` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [rejected\_con\_enabled](#input\_rejected\_con\_enabled) | Flag to enable Redis rejected connections errors monitor | `string` | `"true"` | no | +| [rejected\_con\_extra\_tags](#input\_rejected\_con\_extra\_tags) | Extra tags for Redis rejected connections errors monitor | `list(string)` | `[]` | no | +| [rejected\_con\_message](#input\_rejected\_con\_message) | Custom message for Redis rejected connections errors monitor | `string` | `""` | no | +| [rejected\_con\_threshold\_critical](#input\_rejected\_con\_threshold\_critical) | rejected connections errors limit (critical threshold) | `number` | `50` | no | +| [rejected\_con\_threshold\_warning](#input\_rejected\_con\_threshold\_warning) | rejected connections errors limit (warning threshold) | `number` | `10` | no | +| [rejected\_con\_time\_aggregator](#input\_rejected\_con\_time\_aggregator) | Monitor aggregator for Redis rejected connections errors [available values: min, max or avg] | `string` | `"min"` | no | +| [rejected\_con\_timeframe](#input\_rejected\_con\_timeframe) | Monitor timeframe for Redis rejected connections errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [blocked\_clients\_id](#output\_blocked\_clients\_id) | id for monitor blocked\_clients | +| [evicted\_keys\_id](#output\_evicted\_keys\_id) | id for monitor evicted\_keys | +| [expirations\_id](#output\_expirations\_id) | id for monitor expirations | +| [hitrate\_id](#output\_hitrate\_id) | id for monitor hitrate | +| [keyspace\_full\_id](#output\_keyspace\_full\_id) | id for monitor keyspace\_full | +| [latency\_id](#output\_latency\_id) | id for monitor latency | +| [memory\_frag\_id](#output\_memory\_frag\_id) | id for monitor memory\_frag | +| [memory\_used\_id](#output\_memory\_used\_id) | id for monitor memory\_used | +| [not\_responding\_id](#output\_not\_responding\_id) | id for monitor not\_responding | +| [rejected\_connections\_id](#output\_rejected\_connections\_id) | id for monitor rejected\_connections | +## Related documentation + +[Datadog blog: How to monitor Redis](https://www.datadoghq.com/blog/how-to-monitor-redis-performance-metrics/) + +[Datadog Redis integration doc](https://docs.datadoghq.com/integrations/redisdb/) diff --git a/.terraform/modules/datadog-monitors-system-generic/database/redis/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/database/redis/inputs.tf new file mode 100755 index 0000000..e8ac16b --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/redis/inputs.tf @@ -0,0 +1,442 @@ +# Global Terraform +variable "environment" { + description = "Architecture environment" + type = string +} + +# Global DataDog +variable "message" { + description = "Message sent when a Redis monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds for the metric evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Redis specific variables + +variable "evictedkeys_change_enabled" { + description = "Flag to enable Redis evicted keys monitor" + type = string + default = "true" +} + +variable "evictedkeys_change_message" { + description = "Custom message for Redis evicted keys monitor" + type = string + default = "" +} + +variable "evictedkeys_change_extra_tags" { + description = "Extra tags for Redis evicted keys monitor" + type = list(string) + default = [] +} + +variable "evictedkeys_change_time_aggregator" { + description = "Monitor aggregator for Redis evicted keys [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "evictedkeys_change_timeframe" { + description = "Monitor timeframe for Redis evicted keys [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "evictedkeys_change_threshold_warning" { + description = "Evicted keys change (warning threshold)" + default = 20 +} + +variable "evictedkeys_change_threshold_critical" { + description = "Evicted keys change (critical threshold)" + default = 100 +} + +variable "expirations_rate_enabled" { + description = "Flag to enable Redis keys expirations monitor" + type = string + default = "true" +} + +variable "expirations_rate_message" { + description = "Custom message for Redis keys expirations monitor" + type = string + default = "" +} + +variable "expirations_rate_extra_tags" { + description = "Extra tags for Redis keys expirations monitor" + type = list(string) + default = [] +} + +variable "expirations_rate_time_aggregator" { + description = "Monitor aggregator for Redis keys expirations [available values: min, max or avg]" + type = string + default = "min" +} + +variable "expirations_rate_timeframe" { + description = "Monitor timeframe for Redis keys expirations [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "expirations_rate_threshold_critical" { + description = "Expirations percent (critical threshold)" + default = 80 +} + +variable "expirations_rate_threshold_warning" { + description = "Expirations percent (warning threshold)" + default = 60 +} + +variable "blocked_clients_enabled" { + description = "Flag to enable Redis Blocked clients monitor" + type = string + default = "true" +} + +variable "blocked_clients_message" { + description = "Custom message for Redis Blocked clients monitor" + type = string + default = "" +} + +variable "blocked_clients_extra_tags" { + description = "Extra tags for Redis Blocked clients monitor" + type = list(string) + default = [] +} + +variable "blocked_clients_time_aggregator" { + description = "Monitor aggregator for Redis Blocked clients [available values: min, max or avg]" + type = string + default = "min" +} + +variable "blocked_clients_timeframe" { + description = "Monitor timeframe for Redis Blocked clients [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "blocked_clients_threshold_critical" { + description = "Blocked clients rate (critical threshold)" + default = 30 +} + +variable "blocked_clients_threshold_warning" { + description = "Blocked clients rate (warning threshold)" + default = 10 +} + +variable "keyspace_enabled" { + description = "Flag to enable Redis keyspace monitor" + type = string + default = "true" +} + +variable "keyspace_message" { + description = "Custom message for Redis keyspace monitor" + type = string + default = "" +} + +variable "keyspace_extra_tags" { + description = "Extra tags for Redis keyspace monitor" + type = list(string) + default = [] +} + +variable "keyspace_time_aggregator" { + description = "Monitor aggregator for Redis keyspace [available values: min, max or avg]" + type = string + default = "min" +} + +variable "keyspace_timeframe" { + description = "Monitor timeframe for Redis keyspace [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "keyspace_threshold_critical" { + description = "Keyspace no changement (critical threshold)" + default = 0 +} + +variable "keyspace_threshold_warning" { + description = "Keyspace no changement (warning threshold)" + default = 1 +} + +variable "mem_used_enabled" { + description = "Flag to enable Redis RAM memory used monitor" + type = string + default = "true" +} + +variable "mem_used_message" { + description = "Custom message for Redis RAM memory used monitor" + type = string + default = "" +} + +variable "mem_used_extra_tags" { + description = "Extra tags for Redis RAM memory used monitor" + type = list(string) + default = [] +} + +variable "mem_used_time_aggregator" { + description = "Monitor aggregator for Redis RAM memory used [available values: min, max or avg]" + type = string + default = "min" +} + +variable "mem_used_timeframe" { + description = "Monitor timeframe for Redis RAM memory used [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "mem_used_threshold_critical" { + description = "RAM memory used limit (critical threshold)" + default = 95 +} + +variable "mem_used_threshold_warning" { + description = "RAM memory used limit (warning threshold)" + default = 85 +} + +variable "mem_frag_enabled" { + description = "Flag to enable Redis memory RAM fragmentation monitor" + type = string + default = "true" +} + +variable "mem_frag_message" { + description = "Custom message for Redis memory RAM fragmentation monitor" + type = string + default = "" +} + +variable "mem_frag_extra_tags" { + description = "Extra tags for Redis memory RAM fragmentation monitor" + type = list(string) + default = [] +} + +variable "mem_frag_time_aggregator" { + description = "Monitor aggregator for Redis memory RAM fragmentation [available values: min, max or avg]" + type = string + default = "min" +} + +variable "mem_frag_timeframe" { + description = "Monitor timeframe for Redis memory RAM fragmentation [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "mem_frag_threshold_critical" { + description = "memory RAM fragmentation limit (critical threshold)" + default = 150 +} + +variable "mem_frag_threshold_warning" { + description = "memory RAM fragmentation limit (warning threshold)" + default = 130 +} + +variable "rejected_con_enabled" { + description = "Flag to enable Redis rejected connections errors monitor" + type = string + default = "true" +} + +variable "rejected_con_message" { + description = "Custom message for Redis rejected connections errors monitor" + type = string + default = "" +} + +variable "rejected_con_extra_tags" { + description = "Extra tags for Redis rejected connections errors monitor" + type = list(string) + default = [] +} + +variable "rejected_con_time_aggregator" { + description = "Monitor aggregator for Redis rejected connections errors [available values: min, max or avg]" + type = string + default = "min" +} + +variable "rejected_con_timeframe" { + description = "Monitor timeframe for Redis rejected connections errors [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "rejected_con_threshold_critical" { + description = "rejected connections errors limit (critical threshold)" + default = 50 +} + +variable "rejected_con_threshold_warning" { + description = "rejected connections errors limit (warning threshold)" + default = 10 +} + +variable "latency_enabled" { + description = "Flag to enable Redis latency monitor" + type = string + default = "true" +} + +variable "latency_message" { + description = "Custom message for Redis latency monitor" + type = string + default = "" +} + +variable "latency_extra_tags" { + description = "Extra tags for Redis latency monitor" + type = list(string) + default = [] +} + +variable "latency_time_aggregator" { + description = "Monitor aggregator for Redis latency [available values: min, max or avg]" + type = string + default = "min" +} + +variable "latency_timeframe" { + description = "Monitor timeframe for Redis latency [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "latency_threshold_critical" { + description = "latency limit (critical threshold)" + default = 100 +} + +variable "latency_threshold_warning" { + description = "latency limit (warning threshold)" + default = 50 +} + +variable "hitrate_enabled" { + description = "Flag to enable Redis hitrate monitor" + type = string + default = "true" +} + +variable "hitrate_message" { + description = "Custom message for Redis hitrate monitor" + type = string + default = "" +} + +variable "hitrate_extra_tags" { + description = "Extra tags for Redis hitrate monitor" + type = list(string) + default = [] +} + +variable "hitrate_time_aggregator" { + description = "Monitor aggregator for Redis hitrate [available values: min, max or avg]" + type = string + default = "max" +} + +variable "hitrate_timeframe" { + description = "Monitor timeframe for Redis hitrate [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "hitrate_threshold_critical" { + description = "hitrate limit (critical threshold)" + default = 10 +} + +variable "hitrate_threshold_warning" { + description = "hitrate limit (warning threshold)" + default = 30 +} + +# +# Connection Down +# + +variable "not_responding_enabled" { + description = "Flag to enable Redis does not respond monitor" + type = string + default = "true" +} + +variable "not_responding_message" { + description = "Custom message for Redis does not respond monitor" + type = string + default = "" +} + +variable "not_responding_extra_tags" { + description = "Extra tags for Redis does not respond monitor" + type = list(string) + default = [] +} + +variable "not_responding_threshold_warning" { + description = "Redis does not respond monitor (warning threshold)" + type = string + default = 3 +} + +variable "not_responding_no_data_timeframe" { + description = "Redis does not respond monitor no data timeframe" + type = string + default = 10 +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/database/redis/modules.tf b/.terraform/modules/datadog-monitors-system-generic/database/redis/modules.tf new file mode 100755 index 0000000..f923fe0 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/redis/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "redis" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/database/redis/monitors-redis.tf b/.terraform/modules/datadog-monitors-system-generic/database/redis/monitors-redis.tf new file mode 100755 index 0000000..a05455b --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/redis/monitors-redis.tf @@ -0,0 +1,305 @@ +# +# Service Check +# +resource "datadog_monitor" "not_responding" { + count = var.not_responding_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Redis does not respond" + message = coalesce(var.not_responding_message, var.message) + type = "service check" + + query = < ${var.evictedkeys_change_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.evictedkeys_change_threshold_warning + critical = var.evictedkeys_change_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:database", "provider:redisdb", "resource:redis", "team:claranet", "created-by:terraform"], var.evictedkeys_change_extra_tags) +} + +resource "datadog_monitor" "expirations" { + count = var.expirations_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Redis expired keys {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.expirations_rate_message, var.message) + type = "query alert" + + query = < ${var.expirations_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.expirations_rate_threshold_warning + critical = var.expirations_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:database", "provider:redisdb", "resource:redis", "team:claranet", "created-by:terraform"], var.expirations_rate_extra_tags) +} + +resource "datadog_monitor" "blocked_clients" { + count = var.blocked_clients_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Redis blocked clients {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.blocked_clients_message, var.message) + type = "query alert" + + query = < ${var.blocked_clients_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.blocked_clients_threshold_warning + critical = var.blocked_clients_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:database", "provider:redisdb", "resource:redis", "team:claranet", "created-by:terraform"], var.blocked_clients_extra_tags) +} + +resource "datadog_monitor" "keyspace_full" { + count = var.keyspace_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Redis keyspace seems full (no changes since ${var.keyspace_timeframe})" + message = coalesce(var.keyspace_message, var.message) + type = "query alert" + + query = < ${var.mem_used_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.mem_used_threshold_warning + critical = var.mem_used_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:database", "provider:redisdb", "resource:redis", "team:claranet", "created-by:terraform"], var.mem_used_extra_tags) +} + +resource "datadog_monitor" "memory_frag" { + count = var.mem_frag_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Redis memory fragmented {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.mem_frag_message, var.message) + type = "query alert" + + query = < ${var.mem_frag_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.mem_frag_threshold_warning + critical = var.mem_frag_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:database", "provider:redisdb", "resource:redis", "team:claranet", "created-by:terraform"], var.mem_frag_extra_tags) +} + +resource "datadog_monitor" "rejected_connections" { + count = var.rejected_con_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Redis rejected connections {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.rejected_con_message, var.message) + type = "query alert" + + query = < ${var.rejected_con_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.rejected_con_threshold_warning + critical = var.rejected_con_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:database", "provider:redisdb", "resource:redis", "team:claranet", "created-by:terraform"], var.rejected_con_extra_tags) +} + +resource "datadog_monitor" "latency" { + count = var.latency_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Redis latency {{#is_alert}}{{{comparator}}} {{threshold}}ms ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}ms ({{value}}){{/is_warning}}" + message = coalesce(var.latency_message, var.message) + type = "query alert" + + query = < ${var.latency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.latency_threshold_warning + critical = var.latency_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:database", "provider:redisdb", "resource:redis", "team:claranet", "created-by:terraform"], var.latency_extra_tags) +} + +resource "datadog_monitor" "hitrate" { + count = var.hitrate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Redis hitrate {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.hitrate_message, var.message) + type = "query alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.not_responding](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.search_handler_errors](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.searcher_warmup_time](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before begin to monitor new host | `number` | `300` | no | +| [not\_responding\_enabled](#input\_not\_responding\_enabled) | Flag to enable Solr does not repsond monitor | `bool` | `true` | no | +| [not\_responding\_extra\_tags](#input\_not\_responding\_extra\_tags) | Extra tags for solr does not respond monitor | `list(string)` | `[]` | no | +| [not\_responding\_group\_by](#input\_not\_responding\_group\_by) | Not responding tags to group data | `list(string)` |
[
"instance"
]
| no | +| [not\_responding\_message](#input\_not\_responding\_message) | Custom message for Solr does not respond monitor | `string` | `""` | no | +| [not\_responding\_no\_data\_timeframe](#input\_not\_responding\_no\_data\_timeframe) | Solr not responding monitor no data timeframe | `number` | `10` | no | +| [not\_responding\_threshold\_warning](#input\_not\_responding\_threshold\_warning) | Solr not responding limit (warning threshold) | `number` | `3` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [search\_handler\_errors\_enabled](#input\_search\_handler\_errors\_enabled) | Flag to enable Solr search handler errors monitor | `bool` | `true` | no | +| [search\_handler\_errors\_extra\_tags](#input\_search\_handler\_errors\_extra\_tags) | Extra tags for Search handler errors monitor | `list(string)` | `[]` | no | +| [search\_handler\_errors\_group\_by](#input\_search\_handler\_errors\_group\_by) | Search handler errors tags to group datas | `list(string)` |
[
"instance"
]
| no | +| [search\_handler\_errors\_message](#input\_search\_handler\_errors\_message) | Custom message for Solr search handler errors monitor | `string` | `""` | no | +| [search\_handler\_errors\_rate\_threshold\_critical](#input\_search\_handler\_errors\_rate\_threshold\_critical) | Handler errors rate critical threshold | `number` | `50` | no | +| [search\_handler\_errors\_rate\_threshold\_warning](#input\_search\_handler\_errors\_rate\_threshold\_warning) | Handler errors rate warning threshold | `number` | `10` | no | +| [search\_handler\_errors\_time\_aggregator](#input\_search\_handler\_errors\_time\_aggregator) | Time aggregator for the Handler errors monitor | `string` | `"min"` | no | +| [search\_handler\_errors\_timeframe](#input\_search\_handler\_errors\_timeframe) | Timeframe for the search handler errors monitor | `string` | `"last_5m"` | no | +| [searcher\_warmup\_time\_aggregator](#input\_searcher\_warmup\_time\_aggregator) | Time aggregator for the searcher warmup time monitor | `string` | `"max"` | no | +| [searcher\_warmup\_time\_enabled](#input\_searcher\_warmup\_time\_enabled) | Flag to enable Solr searcher warmup time monitor | `bool` | `true` | no | +| [searcher\_warmup\_time\_extra\_tags](#input\_searcher\_warmup\_time\_extra\_tags) | Extra tags for searcher warmum time monitor | `list(string)` | `[]` | no | +| [searcher\_warmup\_time\_group\_by](#input\_searcher\_warmup\_time\_group\_by) | Search warmup time tags to group datas | `list(string)` |
[
"instance"
]
| no | +| [searcher\_warmup\_time\_message](#input\_searcher\_warmup\_time\_message) | Custom message for Solr searcher warmup time monitor | `string` | `""` | no | +| [searcher\_warmup\_time\_threshold\_critical](#input\_searcher\_warmup\_time\_threshold\_critical) | Searcher warmup time critical threshold in ms | `number` | `5000` | no | +| [searcher\_warmup\_time\_threshold\_warning](#input\_searcher\_warmup\_time\_threshold\_warning) | Searcher warmup time warning threshold in ms | `number` | `2000` | no | +| [searcher\_warmup\_time\_timeframe](#input\_searcher\_warmup\_time\_timeframe) | Timeframe for the searcher warmup time monitor | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [not\_responding\_id](#output\_not\_responding\_id) | id for monitor not\_responding | +| [search\_handler\_errors\_id](#output\_search\_handler\_errors\_id) | id for monitor search\_handler\_errors | +| [searcher\_warmup\_time\_id](#output\_searcher\_warmup\_time\_id) | id for monitor searcher\_warmup\_time | +## Related documentation + + - [Integration Datadog & Solr](https://docs.datadoghq.com/integrations/solr/) diff --git a/.terraform/modules/datadog-monitors-system-generic/database/solr/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/database/solr/inputs.tf new file mode 100755 index 0000000..9e6ac08 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/solr/inputs.tf @@ -0,0 +1,189 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before begin to monitor new host" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + + +# +# Service Check +# +variable "not_responding_enabled" { + type = bool + description = "Flag to enable Solr does not repsond monitor" + default = true +} + +variable "not_responding_group_by" { + type = list(string) + description = "Not responding tags to group data" + default = ["instance"] +} + +variable "not_responding_message" { + description = "Custom message for Solr does not respond monitor" + type = string + default = "" +} + +variable "not_responding_threshold_warning" { + type = number + default = 3 + description = "Solr not responding limit (warning threshold)" +} + +variable "not_responding_no_data_timeframe" { + description = "Solr not responding monitor no data timeframe" + type = number + default = 10 +} + +variable "not_responding_extra_tags" { + description = "Extra tags for solr does not respond monitor" + type = list(string) + default = [] +} + +# +# Handler errors +# +variable "search_handler_errors_enabled" { + description = "Flag to enable Solr search handler errors monitor" + type = bool + default = true +} + +variable "search_handler_errors_group_by" { + description = "Search handler errors tags to group datas" + type = list(string) + default = ["instance"] +} + +variable "search_handler_errors_message" { + description = "Custom message for Solr search handler errors monitor" + type = string + default = "" +} +variable "search_handler_errors_rate_threshold_critical" { + description = "Handler errors rate critical threshold" + default = 50 + type = number +} + +variable "search_handler_errors_rate_threshold_warning" { + description = "Handler errors rate warning threshold" + default = 10 + type = number +} + +variable "search_handler_errors_time_aggregator" { + description = "Time aggregator for the Handler errors monitor" + type = string + default = "min" +} + +variable "search_handler_errors_timeframe" { + description = "Timeframe for the search handler errors monitor" + type = string + default = "last_5m" +} + +variable "search_handler_errors_extra_tags" { + description = "Extra tags for Search handler errors monitor" + default = [] + type = list(string) +} + +# +# Searcher warmup time +# +variable "searcher_warmup_time_enabled" { + default = true + description = "Flag to enable Solr searcher warmup time monitor" + type = bool +} + +variable "searcher_warmup_time_group_by" { + default = ["instance"] + description = "Search warmup time tags to group datas" + type = list(string) +} + +variable "searcher_warmup_time_message" { + description = "Custom message for Solr searcher warmup time monitor" + default = "" + type = string +} + +variable "searcher_warmup_time_threshold_warning" { + description = "Searcher warmup time warning threshold in ms" + # 2sec + default = 2000 + type = number +} + +variable "searcher_warmup_time_threshold_critical" { + description = "Searcher warmup time critical threshold in ms" + # 5 sec + default = 5000 + type = number +} + +variable "searcher_warmup_time_extra_tags" { + description = "Extra tags for searcher warmum time monitor" + default = [] + type = list(string) +} + +variable "searcher_warmup_time_aggregator" { + description = "Time aggregator for the searcher warmup time monitor" + default = "max" + type = string +} + +variable "searcher_warmup_time_timeframe" { + description = "Timeframe for the searcher warmup time monitor" + default = "last_5m" + type = string +} diff --git a/.terraform/modules/datadog-monitors-system-generic/database/solr/modules.tf b/.terraform/modules/datadog-monitors-system-generic/database/solr/modules.tf new file mode 100755 index 0000000..ead22a8 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/solr/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "solr" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} \ No newline at end of file diff --git a/.terraform/modules/datadog-monitors-system-generic/database/solr/monitors-solr.tf b/.terraform/modules/datadog-monitors-system-generic/database/solr/monitors-solr.tf new file mode 100755 index 0000000..06b1cef --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/solr/monitors-solr.tf @@ -0,0 +1,97 @@ +# +# Service Check +# + +resource "datadog_monitor" "not_responding" { + count = var.not_responding_enabled ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Solr does not respond {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.not_responding_message, var.message) + type = "service check" + + query = < ${var.search_handler_errors_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.search_handler_errors_rate_threshold_warning + critical = var.search_handler_errors_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:solr", "resource:solr", "team:claranet", "created-by:terraform"], var.search_handler_errors_extra_tags) + +} + +# +# Solr Warmup time +# + +resource "datadog_monitor" "searcher_warmup_time" { + count = var.searcher_warmup_time_enabled ? 1 : 0 + message = coalesce(var.searcher_warmup_time_message, var.message) + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Solr searcher warmup time too high {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + type = "metric alert" + query = <= ${var.searcher_warmup_time_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.searcher_warmup_time_threshold_warning + critical = var.searcher_warmup_time_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + include_tags = true + require_full_window = true + notify_no_data = false + + tags = concat(["env:${var.environment}", "type:database", "provider:solr", "resource:solr", "team:claranet", "created-by:terraform"], var.searcher_warmup_time_extra_tags) +} diff --git a/.terraform/modules/datadog-monitors-system-generic/database/solr/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/database/solr/outputs.tf new file mode 100755 index 0000000..cdad6c1 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/solr/outputs.tf @@ -0,0 +1,15 @@ +output "not_responding_id" { + description = "id for monitor not_responding" + value = datadog_monitor.not_responding.*.id +} + +output "search_handler_errors_id" { + description = "id for monitor search_handler_errors" + value = datadog_monitor.search_handler_errors.*.id +} + +output "searcher_warmup_time_id" { + description = "id for monitor searcher_warmup_time" + value = datadog_monitor.searcher_warmup_time.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/database/solr/versions.tf b/.terraform/modules/datadog-monitors-system-generic/database/solr/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/solr/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/database/sqlserver/README.md b/.terraform/modules/datadog-monitors-system-generic/database/sqlserver/README.md new file mode 100755 index 0000000..c78785c --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/sqlserver/README.md @@ -0,0 +1,73 @@ +# DATABASE SQLSERVER DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-database-sqlserver" { + source = "claranet/monitors/datadog//database/sqlserver" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- SQL Server server does not respond + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.sqlserver_availability](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds for the metric evaluation | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [sqlserver\_availability\_enabled](#input\_sqlserver\_availability\_enabled) | Flag to enable SQL Server availability monitor | `string` | `"true"` | no | +| [sqlserver\_availability\_extra\_tags](#input\_sqlserver\_availability\_extra\_tags) | Extra tags for SQL Server availability monitor | `list(string)` | `[]` | no | +| [sqlserver\_availability\_message](#input\_sqlserver\_availability\_message) | Custom message for SQL Server availability monitor | `string` | `""` | no | +| [sqlserver\_availability\_no\_data\_timeframe](#input\_sqlserver\_availability\_no\_data\_timeframe) | SQL Server availability monitor no data timeframe | `string` | `10` | no | +| [sqlserver\_availability\_threshold\_warning](#input\_sqlserver\_availability\_threshold\_warning) | SQL Server availability monitor (warning threshold) | `string` | `3` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [sqlserver\_availability\_id](#output\_sqlserver\_availability\_id) | id for monitor sqlserver\_availability | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/sqlserver/](https://docs.datadoghq.com/integrations/sqlserver/) diff --git a/.terraform/modules/datadog-monitors-system-generic/database/sqlserver/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/database/sqlserver/inputs.tf new file mode 100755 index 0000000..378a413 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/sqlserver/inputs.tf @@ -0,0 +1,79 @@ +variable "environment" { + description = "Environment" + type = string +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds for the metric evaluation" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# SQL Server specific + +################################# +### SQL Server availability ### +################################# + +variable "sqlserver_availability_enabled" { + description = "Flag to enable SQL Server availability monitor" + type = string + default = "true" +} + +variable "sqlserver_availability_extra_tags" { + description = "Extra tags for SQL Server availability monitor" + type = list(string) + default = [] +} + +variable "sqlserver_availability_message" { + description = "Custom message for SQL Server availability monitor" + type = string + default = "" +} + +variable "sqlserver_availability_threshold_warning" { + description = "SQL Server availability monitor (warning threshold)" + type = string + default = 3 +} + +variable "sqlserver_availability_no_data_timeframe" { + description = "SQL Server availability monitor no data timeframe" + type = string + default = 10 +} diff --git a/.terraform/modules/datadog-monitors-system-generic/database/sqlserver/modules.tf b/.terraform/modules/datadog-monitors-system-generic/database/sqlserver/modules.tf new file mode 100755 index 0000000..ad2d0d8 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/sqlserver/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "sqlserver" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/database/sqlserver/monitors-sqlserver.tf b/.terraform/modules/datadog-monitors-system-generic/database/sqlserver/monitors-sqlserver.tf new file mode 100755 index 0000000..1e12d6c --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/sqlserver/monitors-sqlserver.tf @@ -0,0 +1,27 @@ +resource "datadog_monitor" "sqlserver_availability" { + count = var.sqlserver_availability_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] SQL Server server does not respond" + message = coalesce(var.sqlserver_availability_message, var.message) + type = "service check" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.datadog_monitor_zookeeper_latency](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.not_responding](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when a monitor is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before begin to monitor new host | `number` | `300` | no | +| [not\_responding\_group\_by](#input\_not\_responding\_group\_by) | List of tags to use to group data | `list(string)` |
[
"host",
"server"
]
| no | +| [not\_responding\_no\_data\_timeframe](#input\_not\_responding\_no\_data\_timeframe) | Zookeeper monitor no\_data\_timeframe | `number` | `10` | no | +| [not\_responding\_notify\_no\_data](#input\_not\_responding\_notify\_no\_data) | Send notification if not\_responding monitor does not retrieve data | `bool` | `true` | no | +| [not\_responding\_threshold\_warning](#input\_not\_responding\_threshold\_warning) | Zookeeper not responding limit (warning threshold) | `number` | `3` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [zookeeper\_latency\_availability\_extra\_tags](#input\_zookeeper\_latency\_availability\_extra\_tags) | Extra tags for zookeeper read latency monitor | `list(string)` | `[]` | no | +| [zookeeper\_latency\_enabled](#input\_zookeeper\_latency\_enabled) | Flag to enable Zookeeper read latency monitor | `string` | `"true"` | no | +| [zookeeper\_latency\_group\_by](#input\_zookeeper\_latency\_group\_by) | Tags to use to group datas | `list(string)` |
[
"host"
]
| no | +| [zookeeper\_latency\_status\_message](#input\_zookeeper\_latency\_status\_message) | Custom message for Zookeeper read latency monitor | `string` | `""` | no | +| [zookeeper\_latency\_threshold\_critical](#input\_zookeeper\_latency\_threshold\_critical) | Maximum critical acceptable ms of zookeeper latency monitor | `number` | `300000` | no | +| [zookeeper\_latency\_threshold\_warning](#input\_zookeeper\_latency\_threshold\_warning) | Maximum warning acceptable ms of zookeeper latency monitor | `number` | `250000` | no | +| [zookeeper\_latency\_time\_aggregator](#input\_zookeeper\_latency\_time\_aggregator) | Monitor time aggregator for Zookeeper read latency monitor [available values: min, max or avg] | `string` | `"avg"` | no | +| [zookeeper\_latency\_timeframe](#input\_zookeeper\_latency\_timeframe) | Monitor timeframe for Zookeeper read latency monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_15m"` | no | +| [zookeeper\_not\_responding\_enabled](#input\_zookeeper\_not\_responding\_enabled) | Flag to enable Zookeeper does not respond monitor | `string` | `"true"` | no | +| [zookeeper\_not\_responding\_extra\_tags](#input\_zookeeper\_not\_responding\_extra\_tags) | Extra tags for Zookeeper does not respond monitor | `list(string)` | `[]` | no | +| [zookeeper\_not\_responding\_message](#input\_zookeeper\_not\_responding\_message) | Custom message for Zookeeper does not respond monitor | `string` | `""` | no | +| [zookeeper\_not\_responding\_time\_aggregator](#input\_zookeeper\_not\_responding\_time\_aggregator) | Time aggregator for the Zookeeper does not respond monitor | `string` | `"avg"` | no | +| [zookeeper\_not\_responding\_timeframe](#input\_zookeeper\_not\_responding\_timeframe) | Timeframe for the does not respond monitor | `string` | `"last_5m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [datadog\_monitor\_zookeeper\_latency\_id](#output\_datadog\_monitor\_zookeeper\_latency\_id) | id for monitor datadog\_monitor\_zookeeper\_latency | +| [not\_responding\_id](#output\_not\_responding\_id) | id for monitor not\_responding | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/zk/](https://docs.datadoghq.com/integrations/zk/) diff --git a/.terraform/modules/datadog-monitors-system-generic/database/zookeeper/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/database/zookeeper/inputs.tf new file mode 100755 index 0000000..3874747 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/zookeeper/inputs.tf @@ -0,0 +1,147 @@ +# +# Datadog global variables +# +variable "environment" { + description = "Architecture environment" + type = string +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +variable "message" { + description = "Message sent when a monitor is triggered" +} + +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before begin to monitor new host" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +# +# Service Check +# +variable "not_responding_notify_no_data" { + default = true + type = bool + description = "Send notification if not_responding monitor does not retrieve data" +} +variable "not_responding_no_data_timeframe" { + default = 10 + description = "Zookeeper monitor no_data_timeframe" + type = number +} + +variable "not_responding_group_by" { + default = ["host", "server"] + type = list(string) + description = "List of tags to use to group data" +} + +variable "zookeeper_not_responding_enabled" { + description = "Flag to enable Zookeeper does not respond monitor" + type = string + default = "true" +} + +variable "zookeeper_not_responding_message" { + description = "Custom message for Zookeeper does not respond monitor" + type = string + default = "" +} + +variable "zookeeper_not_responding_time_aggregator" { + description = "Time aggregator for the Zookeeper does not respond monitor" + type = string + default = "avg" +} + +variable "zookeeper_not_responding_timeframe" { + description = "Timeframe for the does not respond monitor" + type = string + default = "last_5m" +} + +variable "zookeeper_not_responding_extra_tags" { + description = "Extra tags for Zookeeper does not respond monitor" + type = list(string) + default = [] +} + +variable "not_responding_threshold_warning" { + default = 3 + type = number + description = "Zookeeper not responding limit (warning threshold)" +} + +# +# Check read latency monitor +# +variable "zookeeper_latency_enabled" { + description = "Flag to enable Zookeeper read latency monitor" + type = string + default = "true" +} + +variable "zookeeper_latency_group_by" { + description = "Tags to use to group datas" + type = list(string) + default = ["host"] +} + +variable "zookeeper_latency_status_message" { + description = "Custom message for Zookeeper read latency monitor" + type = string + default = "" +} + +variable "zookeeper_latency_time_aggregator" { + description = "Monitor time aggregator for Zookeeper read latency monitor [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "zookeeper_latency_timeframe" { + description = "Monitor timeframe for Zookeeper read latency monitor [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_15m" +} + +variable "zookeeper_latency_threshold_critical" { + description = "Maximum critical acceptable ms of zookeeper latency monitor" + default = 300000 +} + +variable "zookeeper_latency_threshold_warning" { + description = "Maximum warning acceptable ms of zookeeper latency monitor" + default = 250000 +} + +variable "zookeeper_latency_availability_extra_tags" { + description = "Extra tags for zookeeper read latency monitor" + type = list(string) + default = [] +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/database/zookeeper/modules.tf b/.terraform/modules/datadog-monitors-system-generic/database/zookeeper/modules.tf new file mode 100755 index 0000000..f0cf5b4 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/zookeeper/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "zookeeper" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/database/zookeeper/monitors-zookeeper.tf b/.terraform/modules/datadog-monitors-system-generic/database/zookeeper/monitors-zookeeper.tf new file mode 100755 index 0000000..3a32125 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/zookeeper/monitors-zookeeper.tf @@ -0,0 +1,57 @@ +resource "datadog_monitor" "not_responding" { + count = var.zookeeper_not_responding_enabled ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Zookeeper service does not respond {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.zookeeper_not_responding_message, var.message) + type = "service check" + + query = < ${var.zookeeper_latency_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.zookeeper_latency_threshold_warning + critical = var.zookeeper_latency_threshold_critical + } + + notify_no_data = false + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:database", "provider:zookeeper", "resource:zookeeper", "team:claranet", "created-by:terraform"], var.zookeeper_latency_availability_extra_tags) + +} diff --git a/.terraform/modules/datadog-monitors-system-generic/database/zookeeper/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/database/zookeeper/outputs.tf new file mode 100755 index 0000000..f9403da --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/zookeeper/outputs.tf @@ -0,0 +1,10 @@ +output "datadog_monitor_zookeeper_latency_id" { + description = "id for monitor datadog_monitor_zookeeper_latency" + value = datadog_monitor.datadog_monitor_zookeeper_latency.*.id +} + +output "not_responding_id" { + description = "id for monitor not_responding" + value = datadog_monitor.not_responding.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/database/zookeeper/versions.tf b/.terraform/modules/datadog-monitors-system-generic/database/zookeeper/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/database/zookeeper/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/middleware/apache/README.md b/.terraform/modules/datadog-monitors-system-generic/middleware/apache/README.md new file mode 100755 index 0000000..af17369 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/middleware/apache/README.md @@ -0,0 +1,73 @@ +# MIDDLEWARE APACHE DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-middleware-apache" { + source = "claranet/monitors/datadog//middleware/apache" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Apache vhost status does not respond + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.datadog_apache_process](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [apache\_connect\_enabled](#input\_apache\_connect\_enabled) | Flag to enable Apache status monitor | `string` | `"true"` | no | +| [apache\_connect\_extra\_tags](#input\_apache\_connect\_extra\_tags) | Extra tags for Apache process monitor | `list(string)` | `[]` | no | +| [apache\_connect\_message](#input\_apache\_connect\_message) | Custom message for Apache status monitor | `string` | `""` | no | +| [apache\_connect\_threshold\_warning](#input\_apache\_connect\_threshold\_warning) | Apache status monitor (warning threshold) | `string` | `3` | no | +| [datadog\_apache\_process\_no\_data\_timeframe](#input\_datadog\_apache\_process\_no\_data\_timeframe) | Number of minutes before reporting no data | `string` | `10` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [datadog\_apache\_process\_id](#output\_datadog\_apache\_process\_id) | id for monitor datadog\_apache\_process | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/apache/](https://docs.datadoghq.com/integrations/apache/) diff --git a/.terraform/modules/datadog-monitors-system-generic/middleware/apache/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/middleware/apache/inputs.tf new file mode 100755 index 0000000..ed0cf18 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/middleware/apache/inputs.tf @@ -0,0 +1,78 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "datadog_apache_process_no_data_timeframe" { + description = "Number of minutes before reporting no data" + type = string + default = 10 +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Apache Middleware specific + +variable "apache_connect_enabled" { + description = "Flag to enable Apache status monitor" + type = string + default = "true" +} + +variable "apache_connect_extra_tags" { + description = "Extra tags for Apache process monitor" + type = list(string) + default = [] +} + +variable "apache_connect_message" { + description = "Custom message for Apache status monitor" + type = string + default = "" +} + +variable "apache_connect_threshold_warning" { + description = "Apache status monitor (warning threshold)" + type = string + default = 3 +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/middleware/apache/modules.tf b/.terraform/modules/datadog-monitors-system-generic/middleware/apache/modules.tf new file mode 100755 index 0000000..b84aa1b --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/middleware/apache/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "apache" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/middleware/apache/monitors-apache.tf b/.terraform/modules/datadog-monitors-system-generic/middleware/apache/monitors-apache.tf new file mode 100755 index 0000000..abe8811 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/middleware/apache/monitors-apache.tf @@ -0,0 +1,28 @@ +resource "datadog_monitor" "datadog_apache_process" { + count = var.apache_connect_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Apache vhost status does not respond" + message = coalesce(var.apache_connect_message, var.message) + type = "service check" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.not_responding](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.treatment_limit](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [not\_responding\_enabled](#input\_not\_responding\_enabled) | Flag to enable Kong does not respond monitor | `string` | `"true"` | no | +| [not\_responding\_extra\_tags](#input\_not\_responding\_extra\_tags) | Extra tags for Kong does not respond monitor | `list(string)` | `[]` | no | +| [not\_responding\_message](#input\_not\_responding\_message) | Custom message for Kong does not respond monitor | `string` | `""` | no | +| [not\_responding\_no\_data\_timeframe](#input\_not\_responding\_no\_data\_timeframe) | Kong does not respond monitor no data timeframe | `string` | `10` | no | +| [not\_responding\_threshold\_warning](#input\_not\_responding\_threshold\_warning) | Warning threshold for the service check | `string` | `3` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [treatment\_limit\_enabled](#input\_treatment\_limit\_enabled) | Flag to enable Kong Treatment Limit monitor | `string` | `"true"` | no | +| [treatment\_limit\_extra\_tags](#input\_treatment\_limit\_extra\_tags) | Extra tags for Kong Treatment Limit monitor | `list(string)` | `[]` | no | +| [treatment\_limit\_message](#input\_treatment\_limit\_message) | Custom message for the Kong Treatment Limit monitor | `string` | `""` | no | +| [treatment\_limit\_threshold\_critical](#input\_treatment\_limit\_threshold\_critical) | Docker Container Memory Usage critical threshold | `string` | `20` | no | +| [treatment\_limit\_threshold\_warning](#input\_treatment\_limit\_threshold\_warning) | Docker Container Memory Usage warning threshold | `string` | `0` | no | +| [treatment\_limit\_time\_aggregator](#input\_treatment\_limit\_time\_aggregator) | Time aggregator for the Kong Treatment Limit monitor | `string` | `"min"` | no | +| [treatment\_limit\_timeframe](#input\_treatment\_limit\_timeframe) | Timeframe for the Kong Treatment Limit monitor | `string` | `"last_15m"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [not\_responding\_id](#output\_not\_responding\_id) | id for monitor not\_responding | +| [treatment\_limit\_id](#output\_treatment\_limit\_id) | id for monitor treatment\_limit | +## Related documentation + +* [Datadog Kong integration](https://docs.datadoghq.com/integrations/kong/) + diff --git a/.terraform/modules/datadog-monitors-system-generic/middleware/kong/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/middleware/kong/inputs.tf new file mode 100755 index 0000000..06a3a02 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/middleware/kong/inputs.tf @@ -0,0 +1,126 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# +# Not Responding +# + +variable "not_responding_enabled" { + description = "Flag to enable Kong does not respond monitor" + type = string + default = "true" +} + +variable "not_responding_message" { + description = "Custom message for Kong does not respond monitor" + type = string + default = "" +} + +variable "not_responding_threshold_warning" { + description = "Warning threshold for the service check" + type = string + default = 3 +} + +variable "not_responding_no_data_timeframe" { + description = "Kong does not respond monitor no data timeframe" + type = string + default = 10 +} + +variable "not_responding_extra_tags" { + description = "Extra tags for Kong does not respond monitor" + type = list(string) + default = [] +} + +# +# Treatment Limit +# +variable "treatment_limit_enabled" { + description = "Flag to enable Kong Treatment Limit monitor" + type = string + default = "true" +} + +variable "treatment_limit_message" { + description = "Custom message for the Kong Treatment Limit monitor" + type = string + default = "" +} + +variable "treatment_limit_time_aggregator" { + description = "Time aggregator for the Kong Treatment Limit monitor" + type = string + default = "min" +} + +variable "treatment_limit_timeframe" { + description = "Timeframe for the Kong Treatment Limit monitor" + type = string + default = "last_15m" +} + +variable "treatment_limit_threshold_warning" { + description = "Docker Container Memory Usage warning threshold" + type = string + default = 0 +} + +variable "treatment_limit_threshold_critical" { + description = "Docker Container Memory Usage critical threshold" + type = string + default = 20 +} + +variable "treatment_limit_extra_tags" { + description = "Extra tags for Kong Treatment Limit monitor" + type = list(string) + default = [] +} + + diff --git a/.terraform/modules/datadog-monitors-system-generic/middleware/kong/modules.tf b/.terraform/modules/datadog-monitors-system-generic/middleware/kong/modules.tf new file mode 100755 index 0000000..ff44bcb --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/middleware/kong/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "kong" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} diff --git a/.terraform/modules/datadog-monitors-system-generic/middleware/kong/monitors-kong.tf b/.terraform/modules/datadog-monitors-system-generic/middleware/kong/monitors-kong.tf new file mode 100755 index 0000000..c2f9bc7 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/middleware/kong/monitors-kong.tf @@ -0,0 +1,62 @@ +# +# Service Check +# +resource "datadog_monitor" "not_responding" { + count = var.not_responding_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Kong does not respond" + message = coalesce(var.not_responding_message, var.message) + type = "service check" + + query = < ${var.treatment_limit_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.treatment_limit_threshold_warning + critical = var.treatment_limit_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:middleware", "provider:kong", "resource:kong", "team:claranet", "created-by:terraform"], var.treatment_limit_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/middleware/kong/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/middleware/kong/outputs.tf new file mode 100755 index 0000000..cbf2df8 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/middleware/kong/outputs.tf @@ -0,0 +1,10 @@ +output "not_responding_id" { + description = "id for monitor not_responding" + value = datadog_monitor.not_responding.*.id +} + +output "treatment_limit_id" { + description = "id for monitor treatment_limit" + value = datadog_monitor.treatment_limit.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/middleware/kong/versions.tf b/.terraform/modules/datadog-monitors-system-generic/middleware/kong/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/middleware/kong/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/middleware/nginx/README.md b/.terraform/modules/datadog-monitors-system-generic/middleware/nginx/README.md new file mode 100755 index 0000000..3591e85 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/middleware/nginx/README.md @@ -0,0 +1,82 @@ +# MIDDLEWARE NGINX DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-middleware-nginx" { + source = "claranet/monitors/datadog//middleware/nginx" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Nginx dropped connections +- Nginx vhost status does not respond + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.datadog_nginx_dropped_connections](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.datadog_nginx_process](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [nginx\_connect\_enabled](#input\_nginx\_connect\_enabled) | Flag to enable Nginx status monitor | `string` | `"true"` | no | +| [nginx\_connect\_extra\_tags](#input\_nginx\_connect\_extra\_tags) | Extra tags for Nginx process monitor | `list(string)` | `[]` | no | +| [nginx\_connect\_message](#input\_nginx\_connect\_message) | Custom message for Nginx status monitor | `string` | `""` | no | +| [nginx\_connect\_no\_data\_timeframe](#input\_nginx\_connect\_no\_data\_timeframe) | Nginx status monitor no data timeframe | `string` | `10` | no | +| [nginx\_connect\_threshold\_warning](#input\_nginx\_connect\_threshold\_warning) | Nginx status monitor (warning threshold) | `string` | `3` | no | +| [nginx\_dropped\_enabled](#input\_nginx\_dropped\_enabled) | Flag to enable Nginx dropped monitor | `string` | `"true"` | no | +| [nginx\_dropped\_extra\_tags](#input\_nginx\_dropped\_extra\_tags) | Extra tags for Nginx dropped connections monitor | `list(string)` | `[]` | no | +| [nginx\_dropped\_message](#input\_nginx\_dropped\_message) | Custom message for Nginx dropped connections monitor | `string` | `""` | no | +| [nginx\_dropped\_threshold\_critical](#input\_nginx\_dropped\_threshold\_critical) | Nginx dropped connections critical threshold | `number` | `0` | no | +| [nginx\_dropped\_time\_aggregator](#input\_nginx\_dropped\_time\_aggregator) | Monitor aggregator for Nginx dropped connections [available values: min, max or avg] | `string` | `"min"` | no | +| [nginx\_dropped\_timeframe](#input\_nginx\_dropped\_timeframe) | Monitor timeframe for Nginx dropped connections [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [datadog\_nginx\_dropped\_connections\_id](#output\_datadog\_nginx\_dropped\_connections\_id) | id for monitor datadog\_nginx\_dropped\_connections | +| [datadog\_nginx\_process\_id](#output\_datadog\_nginx\_process\_id) | id for monitor datadog\_nginx\_process | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/nginx/](https://docs.datadoghq.com/integrations/nginx/) diff --git a/.terraform/modules/datadog-monitors-system-generic/middleware/nginx/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/middleware/nginx/inputs.tf new file mode 100755 index 0000000..9565887 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/middleware/nginx/inputs.tf @@ -0,0 +1,113 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Nginx Middleware specific + +variable "nginx_connect_enabled" { + description = "Flag to enable Nginx status monitor" + type = string + default = "true" +} + +variable "nginx_connect_extra_tags" { + description = "Extra tags for Nginx process monitor" + type = list(string) + default = [] +} + +variable "nginx_connect_message" { + description = "Custom message for Nginx status monitor" + type = string + default = "" +} + +variable "nginx_connect_threshold_warning" { + description = "Nginx status monitor (warning threshold)" + type = string + default = 3 +} + +variable "nginx_connect_no_data_timeframe" { + description = "Nginx status monitor no data timeframe" + type = string + default = 10 +} + +variable "nginx_dropped_enabled" { + description = "Flag to enable Nginx dropped monitor" + type = string + default = "true" +} + +variable "nginx_dropped_extra_tags" { + description = "Extra tags for Nginx dropped connections monitor" + type = list(string) + default = [] +} + +variable "nginx_dropped_message" { + description = "Custom message for Nginx dropped connections monitor" + type = string + default = "" +} + +variable "nginx_dropped_time_aggregator" { + description = "Monitor aggregator for Nginx dropped connections [available values: min, max or avg]" + type = string + default = "min" +} + +variable "nginx_dropped_timeframe" { + description = "Monitor timeframe for Nginx dropped connections [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "nginx_dropped_threshold_critical" { + description = "Nginx dropped connections critical threshold" + default = 0 +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/middleware/nginx/modules.tf b/.terraform/modules/datadog-monitors-system-generic/middleware/nginx/modules.tf new file mode 100755 index 0000000..3d2b17d --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/middleware/nginx/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "nginx" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/middleware/nginx/monitors-nginx.tf b/.terraform/modules/datadog-monitors-system-generic/middleware/nginx/monitors-nginx.tf new file mode 100755 index 0000000..e94ef15 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/middleware/nginx/monitors-nginx.tf @@ -0,0 +1,56 @@ +resource "datadog_monitor" "datadog_nginx_process" { + count = var.nginx_connect_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Nginx vhost status does not respond" + message = coalesce(var.nginx_connect_message, var.message) + type = "service check" + + query = < ${var.nginx_dropped_threshold_critical} +EOQ + + monitor_thresholds { + critical = var.nginx_dropped_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:middleware", "provider:nginx", "resource:nginx", "team:claranet", "created-by:terraform"], var.nginx_dropped_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/middleware/nginx/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/middleware/nginx/outputs.tf new file mode 100755 index 0000000..60070fd --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/middleware/nginx/outputs.tf @@ -0,0 +1,10 @@ +output "datadog_nginx_dropped_connections_id" { + description = "id for monitor datadog_nginx_dropped_connections" + value = datadog_monitor.datadog_nginx_dropped_connections.*.id +} + +output "datadog_nginx_process_id" { + description = "id for monitor datadog_nginx_process" + value = datadog_monitor.datadog_nginx_process.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/middleware/nginx/versions.tf b/.terraform/modules/datadog-monitors-system-generic/middleware/nginx/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/middleware/nginx/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/middleware/php-fpm/README.md b/.terraform/modules/datadog-monitors-system-generic/middleware/php-fpm/README.md new file mode 100755 index 0000000..b191831 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/middleware/php-fpm/README.md @@ -0,0 +1,83 @@ +# MIDDLEWARE PHP-FPM DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-middleware-php-fpm" { + source = "claranet/monitors/datadog//middleware/php-fpm" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- Php-fpm busy worker +- Php-fpm ping url does not respond + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.php_fpm_connect](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.php_fpm_connect_idle](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [php\_fpm\_busy\_enabled](#input\_php\_fpm\_busy\_enabled) | Flag to enable PHP FPM busy worker monitor | `string` | `"true"` | no | +| [php\_fpm\_busy\_extra\_tags](#input\_php\_fpm\_busy\_extra\_tags) | Extra tags for PHP FPM busy worker monitor | `list(string)` | `[]` | no | +| [php\_fpm\_busy\_message](#input\_php\_fpm\_busy\_message) | Custom message for PHP FPM busy worker monitor | `string` | `""` | no | +| [php\_fpm\_busy\_threshold\_critical](#input\_php\_fpm\_busy\_threshold\_critical) | php fpm busy critical threshold | `number` | `90` | no | +| [php\_fpm\_busy\_threshold\_warning](#input\_php\_fpm\_busy\_threshold\_warning) | php fpm busy warning threshold | `number` | `80` | no | +| [php\_fpm\_busy\_time\_aggregator](#input\_php\_fpm\_busy\_time\_aggregator) | Monitor aggregator for PHP FPM busy worker [available values: min, max or avg] | `string` | `"avg"` | no | +| [php\_fpm\_busy\_timeframe](#input\_php\_fpm\_busy\_timeframe) | Monitor timeframe for PHP FPM busy worker [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_10m"` | no | +| [php\_fpm\_connect\_enabled](#input\_php\_fpm\_connect\_enabled) | Flag to enable PHP FPM status monitor | `string` | `"true"` | no | +| [php\_fpm\_connect\_extra\_tags](#input\_php\_fpm\_connect\_extra\_tags) | Extra tags for PHP FPM status monitor | `list(string)` | `[]` | no | +| [php\_fpm\_connect\_message](#input\_php\_fpm\_connect\_message) | Custom message for PHP FPM status monitor | `string` | `""` | no | +| [php\_fpm\_connect\_no\_data\_timeframe](#input\_php\_fpm\_connect\_no\_data\_timeframe) | PHP FPM status monitor no data timeframe | `string` | `10` | no | +| [php\_fpm\_connect\_threshold\_warning](#input\_php\_fpm\_connect\_threshold\_warning) | PHP FPM status monitor (warning threshold) | `string` | `3` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [php\_fpm\_connect\_id](#output\_php\_fpm\_connect\_id) | id for monitor php\_fpm\_connect | +| [php\_fpm\_connect\_idle\_id](#output\_php\_fpm\_connect\_idle\_id) | id for monitor php\_fpm\_connect\_idle | +## Related documentation + +DataDog documentation: [https://docs.datadoghq.com/integrations/php_fpm/](https://docs.datadoghq.com/integrations/php_fpm/) diff --git a/.terraform/modules/datadog-monitors-system-generic/middleware/php-fpm/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/middleware/php-fpm/inputs.tf new file mode 100755 index 0000000..a4e05bb --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/middleware/php-fpm/inputs.tf @@ -0,0 +1,118 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# PHP FPM Middleware specific + +variable "php_fpm_busy_enabled" { + description = "Flag to enable PHP FPM busy worker monitor" + type = string + default = "true" +} + +variable "php_fpm_busy_extra_tags" { + description = "Extra tags for PHP FPM busy worker monitor" + type = list(string) + default = [] +} + +variable "php_fpm_busy_message" { + description = "Custom message for PHP FPM busy worker monitor" + type = string + default = "" +} + +variable "php_fpm_busy_time_aggregator" { + description = "Monitor aggregator for PHP FPM busy worker [available values: min, max or avg]" + type = string + default = "avg" +} + +variable "php_fpm_busy_timeframe" { + description = "Monitor timeframe for PHP FPM busy worker [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_10m" +} + +variable "php_fpm_busy_threshold_warning" { + description = "php fpm busy warning threshold" + default = 80 +} + +variable "php_fpm_busy_threshold_critical" { + description = "php fpm busy critical threshold" + default = 90 +} + +variable "php_fpm_connect_enabled" { + description = "Flag to enable PHP FPM status monitor" + type = string + default = "true" +} + +variable "php_fpm_connect_extra_tags" { + description = "Extra tags for PHP FPM status monitor" + type = list(string) + default = [] +} + +variable "php_fpm_connect_message" { + description = "Custom message for PHP FPM status monitor" + type = string + default = "" +} + +variable "php_fpm_connect_threshold_warning" { + description = "PHP FPM status monitor (warning threshold)" + type = string + default = 3 +} + +variable "php_fpm_connect_no_data_timeframe" { + description = "PHP FPM status monitor no data timeframe" + type = string + default = 10 +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/middleware/php-fpm/modules.tf b/.terraform/modules/datadog-monitors-system-generic/middleware/php-fpm/modules.tf new file mode 100755 index 0000000..9d90639 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/middleware/php-fpm/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "php-fpm" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/middleware/php-fpm/monitors-fpm.tf b/.terraform/modules/datadog-monitors-system-generic/middleware/php-fpm/monitors-fpm.tf new file mode 100755 index 0000000..3ef7883 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/middleware/php-fpm/monitors-fpm.tf @@ -0,0 +1,59 @@ +resource "datadog_monitor" "php_fpm_connect" { + count = var.php_fpm_connect_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Php-fpm ping url does not respond" + message = coalesce(var.php_fpm_connect_message, var.message) + type = "service check" + + query = < ${var.php_fpm_busy_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.php_fpm_busy_threshold_warning + critical = var.php_fpm_busy_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:middleware", "provider:php-fpm", "resource:php-fpm", "team:claranet", "created-by:terraform"], var.php_fpm_busy_extra_tags) +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/middleware/php-fpm/outputs.tf b/.terraform/modules/datadog-monitors-system-generic/middleware/php-fpm/outputs.tf new file mode 100755 index 0000000..1d7408a --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/middleware/php-fpm/outputs.tf @@ -0,0 +1,10 @@ +output "php_fpm_connect_id" { + description = "id for monitor php_fpm_connect" + value = datadog_monitor.php_fpm_connect.*.id +} + +output "php_fpm_connect_idle_id" { + description = "id for monitor php_fpm_connect_idle" + value = datadog_monitor.php_fpm_connect_idle.*.id +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/middleware/php-fpm/versions.tf b/.terraform/modules/datadog-monitors-system-generic/middleware/php-fpm/versions.tf new file mode 100755 index 0000000..a5c6a87 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/middleware/php-fpm/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + datadog = { + source = "DataDog/datadog" + version = ">= 3.1.0" + } + } + required_version = ">= 0.12.31" +} diff --git a/.terraform/modules/datadog-monitors-system-generic/network/dns/README.md b/.terraform/modules/datadog-monitors-system-generic/network/dns/README.md new file mode 100755 index 0000000..4e0e5b6 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/network/dns/README.md @@ -0,0 +1,73 @@ +# NETWORK DNS DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-network-dns" { + source = "claranet/monitors/datadog//network/dns" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- DNS cannot resolve + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cannot_resolve](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cannot\_resolve\_enabled](#input\_cannot\_resolve\_enabled) | Flag to enable DNS cannot resolve monitor | `string` | `"true"` | no | +| [cannot\_resolve\_extra\_tags](#input\_cannot\_resolve\_extra\_tags) | Extra tags for DNS cannot resolve monitor | `list(string)` | `[]` | no | +| [cannot\_resolve\_message](#input\_cannot\_resolve\_message) | Custom message for DNS cannot resolve monitor | `string` | `""` | no | +| [cannot\_resolve\_no\_data\_timeframe](#input\_cannot\_resolve\_no\_data\_timeframe) | DNS cannot resolve monitor no data timeframe | `string` | `10` | no | +| [cannot\_resolve\_threshold\_warning](#input\_cannot\_resolve\_threshold\_warning) | DNS cannot resolve monitor (warning threshold) | `string` | `3` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cannot\_resolve\_id](#output\_cannot\_resolve\_id) | id for monitor cannot\_resolve | +## Related documentation + +- [Datadog DNS integration](https://docs.datadoghq.com/integrations/dns_check/) diff --git a/.terraform/modules/datadog-monitors-system-generic/network/dns/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/network/dns/inputs.tf new file mode 100755 index 0000000..c00e0f3 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/network/dns/inputs.tf @@ -0,0 +1,78 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# +# Cannot Resolve +# +variable "cannot_resolve_enabled" { + description = "Flag to enable DNS cannot resolve monitor" + type = string + default = "true" +} + +variable "cannot_resolve_message" { + description = "Custom message for DNS cannot resolve monitor" + type = string + default = "" +} + +variable "cannot_resolve_threshold_warning" { + description = "DNS cannot resolve monitor (warning threshold)" + type = string + default = 3 +} + +variable "cannot_resolve_no_data_timeframe" { + description = "DNS cannot resolve monitor no data timeframe" + type = string + default = 10 +} + +variable "cannot_resolve_extra_tags" { + description = "Extra tags for DNS cannot resolve monitor" + type = list(string) + default = [] +} \ No newline at end of file diff --git a/.terraform/modules/datadog-monitors-system-generic/network/dns/modules.tf b/.terraform/modules/datadog-monitors-system-generic/network/dns/modules.tf new file mode 100755 index 0000000..03747be --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/network/dns/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "dns" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} diff --git a/.terraform/modules/datadog-monitors-system-generic/network/dns/monitors-dns.tf b/.terraform/modules/datadog-monitors-system-generic/network/dns/monitors-dns.tf new file mode 100755 index 0000000..187ce96 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/network/dns/monitors-dns.tf @@ -0,0 +1,30 @@ +# +# Service Check +# +resource "datadog_monitor" "cannot_resolve" { + count = var.cannot_resolve_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] DNS cannot resolve" + message = coalesce(var.cannot_resolve_message, var.message) + type = "service check" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.certificate_expiration_date](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.invalid_ssl_certificate](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [certificate\_expiration\_date\_enabled](#input\_certificate\_expiration\_date\_enabled) | Flag to enable Certificate Expiration Date monitor | `string` | `"false"` | no | +| [certificate\_expiration\_date\_extra\_tags](#input\_certificate\_expiration\_date\_extra\_tags) | Extra tags for Certificate Expiration Date monitor | `list(string)` | `[]` | no | +| [certificate\_expiration\_date\_message](#input\_certificate\_expiration\_date\_message) | Custom message for the Certificate Expiration Date monitor | `string` | `""` | no | +| [certificate\_expiration\_date\_threshold\_critical](#input\_certificate\_expiration\_date\_threshold\_critical) | Certificate Expiration Date critical threshold | `string` | `15` | no | +| [certificate\_expiration\_date\_threshold\_warning](#input\_certificate\_expiration\_date\_threshold\_warning) | Certificate Expiration Date warning threshold | `string` | `30` | no | +| [certificate\_expiration\_date\_time\_aggregator](#input\_certificate\_expiration\_date\_time\_aggregator) | Time aggregator for the Certificate Expiration Date monitor | `string` | `"max"` | no | +| [certificate\_expiration\_date\_timeframe](#input\_certificate\_expiration\_date\_timeframe) | Timeframe for the Certificate Expiration Date monitor | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [invalid\_ssl\_certificate\_enabled](#input\_invalid\_ssl\_certificate\_enabled) | Flag to enable SSL invalid certificate monitor | `string` | `"true"` | no | +| [invalid\_ssl\_certificate\_extra\_tags](#input\_invalid\_ssl\_certificate\_extra\_tags) | Extra tags for SSL invalid certificate monitor | `list(string)` | `[]` | no | +| [invalid\_ssl\_certificate\_message](#input\_invalid\_ssl\_certificate\_message) | Custom message for SSL invalid certificate monitor | `string` | `""` | no | +| [invalid\_ssl\_certificate\_no\_data\_timeframe](#input\_invalid\_ssl\_certificate\_no\_data\_timeframe) | SSL invalid certificate monitor no data timeframe | `string` | `10` | no | +| [invalid\_ssl\_certificate\_threshold\_warning](#input\_invalid\_ssl\_certificate\_threshold\_warning) | SSL invalid certificate monitor (warning threshold) | `string` | `3` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [certificate\_expiration\_date\_id](#output\_certificate\_expiration\_date\_id) | id for monitor certificate\_expiration\_date | +| [invalid\_ssl\_certificate\_id](#output\_invalid\_ssl\_certificate\_id) | id for monitor invalid\_ssl\_certificate | +## Related documentation + diff --git a/.terraform/modules/datadog-monitors-system-generic/network/http/ssl/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/network/http/ssl/inputs.tf new file mode 100755 index 0000000..5ce2426 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/network/http/ssl/inputs.tf @@ -0,0 +1,123 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# +# SSL invalid certificate +# +variable "invalid_ssl_certificate_enabled" { + description = "Flag to enable SSL invalid certificate monitor" + type = string + default = "true" +} + +variable "invalid_ssl_certificate_message" { + description = "Custom message for SSL invalid certificate monitor" + type = string + default = "" +} + +variable "invalid_ssl_certificate_threshold_warning" { + description = "SSL invalid certificate monitor (warning threshold)" + type = string + default = 3 +} + +variable "invalid_ssl_certificate_no_data_timeframe" { + description = "SSL invalid certificate monitor no data timeframe" + type = string + default = 10 +} + +variable "invalid_ssl_certificate_extra_tags" { + description = "Extra tags for SSL invalid certificate monitor" + type = list(string) + default = [] +} + +# +# Certificate Expiration Date +# +variable "certificate_expiration_date_enabled" { + description = "Flag to enable Certificate Expiration Date monitor" + type = string + default = "false" +} + +variable "certificate_expiration_date_message" { + description = "Custom message for the Certificate Expiration Date monitor" + type = string + default = "" +} + +variable "certificate_expiration_date_time_aggregator" { + description = "Time aggregator for the Certificate Expiration Date monitor" + type = string + default = "max" +} + +variable "certificate_expiration_date_timeframe" { + description = "Timeframe for the Certificate Expiration Date monitor" + type = string + default = "last_5m" +} + +variable "certificate_expiration_date_threshold_warning" { + description = "Certificate Expiration Date warning threshold" + type = string + default = 30 +} + +variable "certificate_expiration_date_threshold_critical" { + description = "Certificate Expiration Date critical threshold" + type = string + default = 15 +} + +variable "certificate_expiration_date_extra_tags" { + description = "Extra tags for Certificate Expiration Date monitor" + type = list(string) + default = [] +} \ No newline at end of file diff --git a/.terraform/modules/datadog-monitors-system-generic/network/http/ssl/modules.tf b/.terraform/modules/datadog-monitors-system-generic/network/http/ssl/modules.tf new file mode 100755 index 0000000..1a8b9bf --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/network/http/ssl/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "http" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} diff --git a/.terraform/modules/datadog-monitors-system-generic/network/http/ssl/monitors-ssl.tf b/.terraform/modules/datadog-monitors-system-generic/network/http/ssl/monitors-ssl.tf new file mode 100755 index 0000000..78d65c0 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/network/http/ssl/monitors-ssl.tf @@ -0,0 +1,63 @@ +# +# Invalid SSL Certificate +# +resource "datadog_monitor" "invalid_ssl_certificate" { + count = var.invalid_ssl_certificate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] SSL invalid certificate" + message = coalesce(var.invalid_ssl_certificate_message, var.message) + type = "service check" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cannot_connect](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cannot\_connect\_enabled](#input\_cannot\_connect\_enabled) | Flag to enable HTTP cannot connect monitor | `string` | `"true"` | no | +| [cannot\_connect\_extra\_tags](#input\_cannot\_connect\_extra\_tags) | Extra tags for HTTP cannot connect monitor | `list(string)` | `[]` | no | +| [cannot\_connect\_message](#input\_cannot\_connect\_message) | Custom message for HTTP cannot connect monitor | `string` | `""` | no | +| [cannot\_connect\_no\_data\_timeframe](#input\_cannot\_connect\_no\_data\_timeframe) | HTTP cannot connect monitor no data timeframe | `string` | `10` | no | +| [cannot\_connect\_threshold\_warning](#input\_cannot\_connect\_threshold\_warning) | HTTP cannot connect monitor (warning threshold) | `string` | `3` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cannot\_connect\_id](#output\_cannot\_connect\_id) | id for monitor cannot\_connect | +## Related documentation + diff --git a/.terraform/modules/datadog-monitors-system-generic/network/http/webcheck/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/network/http/webcheck/inputs.tf new file mode 100755 index 0000000..ad7564b --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/network/http/webcheck/inputs.tf @@ -0,0 +1,78 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# +# HTTP Cannot Connect +# +variable "cannot_connect_enabled" { + description = "Flag to enable HTTP cannot connect monitor" + type = string + default = "true" +} + +variable "cannot_connect_message" { + description = "Custom message for HTTP cannot connect monitor" + type = string + default = "" +} + +variable "cannot_connect_threshold_warning" { + description = "HTTP cannot connect monitor (warning threshold)" + type = string + default = 3 +} + +variable "cannot_connect_no_data_timeframe" { + description = "HTTP cannot connect monitor no data timeframe" + type = string + default = 10 +} + +variable "cannot_connect_extra_tags" { + description = "Extra tags for HTTP cannot connect monitor" + type = list(string) + default = [] +} \ No newline at end of file diff --git a/.terraform/modules/datadog-monitors-system-generic/network/http/webcheck/modules.tf b/.terraform/modules/datadog-monitors-system-generic/network/http/webcheck/modules.tf new file mode 100755 index 0000000..1a8b9bf --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/network/http/webcheck/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../../common/filter-tags" + + environment = var.environment + resource = "http" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} diff --git a/.terraform/modules/datadog-monitors-system-generic/network/http/webcheck/monitors-webcheck.tf b/.terraform/modules/datadog-monitors-system-generic/network/http/webcheck/monitors-webcheck.tf new file mode 100755 index 0000000..fc785c9 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/network/http/webcheck/monitors-webcheck.tf @@ -0,0 +1,30 @@ +# +# HTTP Cannot Connect +# +resource "datadog_monitor" "cannot_connect" { + count = var.cannot_connect_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] HTTP cannot connect" + message = coalesce(var.cannot_connect_message, var.message) + type = "service check" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cannot_connect](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.certificate_expiration_date](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.invalid_tls_certificate](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.tls_certificate_expiration](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cannot\_connect\_enabled](#input\_cannot\_connect\_enabled) | Flag to enable TLS cannot connect monitor | `string` | `"true"` | no | +| [cannot\_connect\_extra\_tags](#input\_cannot\_connect\_extra\_tags) | Extra tags for TLS cannot connect monitor | `list(string)` | `[]` | no | +| [cannot\_connect\_message](#input\_cannot\_connect\_message) | Custom message for TLS cannot connect monitor | `string` | `""` | no | +| [cannot\_connect\_no\_data\_timeframe](#input\_cannot\_connect\_no\_data\_timeframe) | TLS cannot connect monitor no data timeframe | `string` | `10` | no | +| [cannot\_connect\_threshold\_warning](#input\_cannot\_connect\_threshold\_warning) | TLS cannot connect monitor (warning threshold) | `string` | `3` | no | +| [certificate\_expiration\_date\_enabled](#input\_certificate\_expiration\_date\_enabled) | Flag to enable Certificate Expiration Date monitor | `string` | `"false"` | no | +| [certificate\_expiration\_date\_extra\_tags](#input\_certificate\_expiration\_date\_extra\_tags) | Extra tags for Certificate Expiration Date monitor | `list(string)` | `[]` | no | +| [certificate\_expiration\_date\_message](#input\_certificate\_expiration\_date\_message) | Custom message for the Certificate Expiration Date monitor | `string` | `""` | no | +| [certificate\_expiration\_date\_threshold\_critical](#input\_certificate\_expiration\_date\_threshold\_critical) | Container Memory Usage critical threshold | `string` | `15` | no | +| [certificate\_expiration\_date\_threshold\_warning](#input\_certificate\_expiration\_date\_threshold\_warning) | Container Memory Usage warning threshold | `string` | `30` | no | +| [certificate\_expiration\_date\_time\_aggregator](#input\_certificate\_expiration\_date\_time\_aggregator) | Time aggregator for the Certificate Expiration Date monitor | `string` | `"max"` | no | +| [certificate\_expiration\_date\_timeframe](#input\_certificate\_expiration\_date\_timeframe) | Timeframe for the Certificate Expiration Date monitor | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [invalid\_tls\_certificate\_enabled](#input\_invalid\_tls\_certificate\_enabled) | Flag to enable TLS certificate expiration monitor | `string` | `"true"` | no | +| [invalid\_tls\_certificate\_extra\_tags](#input\_invalid\_tls\_certificate\_extra\_tags) | Extra tags for TLS certificate expiration monitor | `list(string)` | `[]` | no | +| [invalid\_tls\_certificate\_message](#input\_invalid\_tls\_certificate\_message) | Custom message for TLS certificate expiration monitor | `string` | `""` | no | +| [invalid\_tls\_certificate\_threshold\_warning](#input\_invalid\_tls\_certificate\_threshold\_warning) | TLS certificate expiration monitor (warning threshold) | `string` | `3` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [tls\_certificate\_expiration\_enabled](#input\_tls\_certificate\_expiration\_enabled) | Flag to enable TLS certificate expiration monitor | `string` | `"true"` | no | +| [tls\_certificate\_expiration\_extra\_tags](#input\_tls\_certificate\_expiration\_extra\_tags) | Extra tags for TLS certificate expiration monitor | `list(string)` | `[]` | no | +| [tls\_certificate\_expiration\_message](#input\_tls\_certificate\_expiration\_message) | Custom message for TLS certificate expiration monitor | `string` | `""` | no | +| [tls\_certificate\_expiration\_threshold\_warning](#input\_tls\_certificate\_expiration\_threshold\_warning) | TLS certificate expiration monitor (warning threshold) | `string` | `5` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cannot\_connect\_id](#output\_cannot\_connect\_id) | id for monitor cannot\_connect | +| [certificate\_expiration\_date\_id](#output\_certificate\_expiration\_date\_id) | id for monitor certificate\_expiration\_date | +| [invalid\_tls\_certificate\_id](#output\_invalid\_tls\_certificate\_id) | id for monitor invalid\_tls\_certificate | +| [tls\_certificate\_expiration\_id](#output\_tls\_certificate\_expiration\_id) | id for monitor tls\_certificate\_expiration | +## Related documentation + +- [Datadog TLS integration](https://docs.datadoghq.com/integrations/tls/) + diff --git a/.terraform/modules/datadog-monitors-system-generic/network/tls/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/network/tls/inputs.tf new file mode 100755 index 0000000..cb0ecde --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/network/tls/inputs.tf @@ -0,0 +1,177 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# +# TLS Cannot Connect +# +variable "cannot_connect_enabled" { + description = "Flag to enable TLS cannot connect monitor" + type = string + default = "true" +} + +variable "cannot_connect_message" { + description = "Custom message for TLS cannot connect monitor" + type = string + default = "" +} + +variable "cannot_connect_threshold_warning" { + description = "TLS cannot connect monitor (warning threshold)" + type = string + default = 3 +} + +variable "cannot_connect_no_data_timeframe" { + description = "TLS cannot connect monitor no data timeframe" + type = string + default = 10 +} + +variable "cannot_connect_extra_tags" { + description = "Extra tags for TLS cannot connect monitor" + type = list(string) + default = [] +} + +# +# TLS invalid certificate +# +variable "invalid_tls_certificate_enabled" { + description = "Flag to enable TLS certificate expiration monitor" + type = string + default = "true" +} + +variable "invalid_tls_certificate_message" { + description = "Custom message for TLS certificate expiration monitor" + type = string + default = "" +} + +variable "invalid_tls_certificate_threshold_warning" { + description = "TLS certificate expiration monitor (warning threshold)" + type = string + default = 3 +} + +variable "invalid_tls_certificate_extra_tags" { + description = "Extra tags for TLS certificate expiration monitor" + type = list(string) + default = [] +} + +# +# TLS Certificate Expiration +# +variable "tls_certificate_expiration_enabled" { + description = "Flag to enable TLS certificate expiration monitor" + type = string + default = "true" +} + +variable "tls_certificate_expiration_message" { + description = "Custom message for TLS certificate expiration monitor" + type = string + default = "" +} + +variable "tls_certificate_expiration_threshold_warning" { + description = "TLS certificate expiration monitor (warning threshold)" + type = string + default = 5 +} + +variable "tls_certificate_expiration_extra_tags" { + description = "Extra tags for TLS certificate expiration monitor" + type = list(string) + default = [] +} + +# +# Certificate Expiration Date +# +variable "certificate_expiration_date_enabled" { + description = "Flag to enable Certificate Expiration Date monitor" + type = string + default = "false" +} + +variable "certificate_expiration_date_message" { + description = "Custom message for the Certificate Expiration Date monitor" + type = string + default = "" +} + +variable "certificate_expiration_date_time_aggregator" { + description = "Time aggregator for the Certificate Expiration Date monitor" + type = string + default = "max" +} + +variable "certificate_expiration_date_timeframe" { + description = "Timeframe for the Certificate Expiration Date monitor" + type = string + default = "last_5m" +} + +variable "certificate_expiration_date_threshold_warning" { + description = "Container Memory Usage warning threshold" + type = string + default = 30 +} + +variable "certificate_expiration_date_threshold_critical" { + description = "Container Memory Usage critical threshold" + type = string + default = 15 +} + +variable "certificate_expiration_date_extra_tags" { + description = "Extra tags for Certificate Expiration Date monitor" + type = list(string) + default = [] +} \ No newline at end of file diff --git a/.terraform/modules/datadog-monitors-system-generic/network/tls/modules.tf b/.terraform/modules/datadog-monitors-system-generic/network/tls/modules.tf new file mode 100755 index 0000000..941bec4 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/network/tls/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "tls" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} diff --git a/.terraform/modules/datadog-monitors-system-generic/network/tls/monitors-tls.tf b/.terraform/modules/datadog-monitors-system-generic/network/tls/monitors-tls.tf new file mode 100755 index 0000000..35df142 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/network/tls/monitors-tls.tf @@ -0,0 +1,124 @@ +# +# TLS Cannot Connect +# +resource "datadog_monitor" "cannot_connect" { + count = var.cannot_connect_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] TLS cannot connect" + message = coalesce(var.cannot_connect_message, var.message) + type = "service check" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.app_apdex_score](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.app_error_rate](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [app\_apdex\_score\_enabled](#input\_app\_apdex\_score\_enabled) | Flag to enable APP Apdex Score monitor | `string` | `"true"` | no | +| [app\_apdex\_score\_extra\_tags](#input\_app\_apdex\_score\_extra\_tags) | Extra tags for New Relic APP Apdex Score monitor | `list(string)` | `[]` | no | +| [app\_apdex\_score\_message](#input\_app\_apdex\_score\_message) | Custom message for the APP Apdex Score monitor | `string` | `""` | no | +| [app\_apdex\_score\_threshold\_critical](#input\_app\_apdex\_score\_threshold\_critical) | APP Apdex Score critical threshold | `string` | `0.25` | no | +| [app\_apdex\_score\_threshold\_warning](#input\_app\_apdex\_score\_threshold\_warning) | APP Apdex Score warning threshold | `string` | `0.5` | no | +| [app\_apdex\_score\_time\_aggregator](#input\_app\_apdex\_score\_time\_aggregator) | Time aggregator for the APP Apdex Score monitor | `string` | `"avg"` | no | +| [app\_apdex\_score\_timeframe](#input\_app\_apdex\_score\_timeframe) | Timeframe for the APP Apdex Score monitor | `string` | `"last_15m"` | no | +| [app\_error\_rate\_enabled](#input\_app\_error\_rate\_enabled) | Flag to enable APP Error Rate monitor | `string` | `"true"` | no | +| [app\_error\_rate\_extra\_tags](#input\_app\_error\_rate\_extra\_tags) | Extra tags for New Relic APP Error Rate monitor | `list(string)` | `[]` | no | +| [app\_error\_rate\_message](#input\_app\_error\_rate\_message) | Custom message for the APP Error Rate monitor | `string` | `""` | no | +| [app\_error\_rate\_threshold\_critical](#input\_app\_error\_rate\_threshold\_critical) | APP Error Rate critical threshold | `string` | `5` | no | +| [app\_error\_rate\_threshold\_warning](#input\_app\_error\_rate\_threshold\_warning) | APP Error Rate warning threshold | `string` | `1` | no | +| [app\_error\_rate\_time\_aggregator](#input\_app\_error\_rate\_time\_aggregator) | Time aggregator for the APP Error Rate monitor | `string` | `"min"` | no | +| [app\_error\_rate\_timeframe](#input\_app\_error\_rate\_timeframe) | Timeframe for the APP Error Rate monitor | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `900` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [app\_apdex\_score\_id](#output\_app\_apdex\_score\_id) | id for monitor app\_apdex\_score | +| [app\_error\_rate\_id](#output\_app\_error\_rate\_id) | id for monitor app\_error\_rate | +## Related documentation + +* [Datadog New Relic integration](https://docs.datadoghq.com/integrations/new_relic/) + + diff --git a/.terraform/modules/datadog-monitors-system-generic/saas/new-relic/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/saas/new-relic/inputs.tf new file mode 100755 index 0000000..473a4eb --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/saas/new-relic/inputs.tf @@ -0,0 +1,135 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 900 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# +# APP Error Rate +# +variable "app_error_rate_enabled" { + description = "Flag to enable APP Error Rate monitor" + type = string + default = "true" +} + +variable "app_error_rate_message" { + description = "Custom message for the APP Error Rate monitor" + type = string + default = "" +} + +variable "app_error_rate_time_aggregator" { + description = "Time aggregator for the APP Error Rate monitor" + type = string + default = "min" +} + +variable "app_error_rate_timeframe" { + description = "Timeframe for the APP Error Rate monitor" + type = string + default = "last_5m" +} + +variable "app_error_rate_threshold_warning" { + description = "APP Error Rate warning threshold" + type = string + default = 1 +} + +variable "app_error_rate_threshold_critical" { + description = "APP Error Rate critical threshold" + type = string + default = 5 +} + +variable "app_error_rate_extra_tags" { + description = "Extra tags for New Relic APP Error Rate monitor" + type = list(string) + default = [] +} + +# +# APP Apdex Score +# +variable "app_apdex_score_enabled" { + description = "Flag to enable APP Apdex Score monitor" + type = string + default = "true" +} + +variable "app_apdex_score_message" { + description = "Custom message for the APP Apdex Score monitor" + type = string + default = "" +} + +variable "app_apdex_score_time_aggregator" { + description = "Time aggregator for the APP Apdex Score monitor" + type = string + default = "avg" +} + +variable "app_apdex_score_timeframe" { + description = "Timeframe for the APP Apdex Score monitor" + type = string + default = "last_15m" +} + +variable "app_apdex_score_threshold_warning" { + description = "APP Apdex Score warning threshold" + type = string + default = 0.5 +} + +variable "app_apdex_score_threshold_critical" { + description = "APP Apdex Score critical threshold" + type = string + default = 0.25 +} + +variable "app_apdex_score_extra_tags" { + description = "Extra tags for New Relic APP Apdex Score monitor" + type = list(string) + default = [] +} diff --git a/.terraform/modules/datadog-monitors-system-generic/saas/new-relic/modules.tf b/.terraform/modules/datadog-monitors-system-generic/saas/new-relic/modules.tf new file mode 100755 index 0000000..7e6a157 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/saas/new-relic/modules.tf @@ -0,0 +1,9 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "new_relic" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} diff --git a/.terraform/modules/datadog-monitors-system-generic/saas/new-relic/monitors-new-relic.tf b/.terraform/modules/datadog-monitors-system-generic/saas/new-relic/monitors-new-relic.tf new file mode 100755 index 0000000..05080aa --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/saas/new-relic/monitors-new-relic.tf @@ -0,0 +1,59 @@ +resource "datadog_monitor" "app_error_rate" { + count = var.app_error_rate_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] New Relic Error rate {{#is_alert}}{{{comparator}}} {{threshold}}errs/min ({{value}}errs/min){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}errs/min ({{value}}errs/min){{/is_warning}}" + message = coalesce(var.app_error_rate_message, var.message) + type = "query alert" + + query = < ${var.app_error_rate_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.app_error_rate_threshold_warning + critical = var.app_error_rate_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + renotify_interval = 0 + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = false + + tags = concat(["env:${var.environment}", "type:saas", "provider:new-relic", "resource:new-relic", "team:claranet", "created-by:terraform"], var.app_error_rate_extra_tags) +} + +resource "datadog_monitor" "app_apdex_score" { + count = var.app_apdex_score_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] New Relic Apdex score ratio {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.app_apdex_score_message, var.message) + type = "query alert" + + query = < /dev/null 2>&1; then + echo "This requires ${cmd} command, please install it first." + exit 1 + fi +} + +function verlte() { + [ "$1" = "$(echo -e "$1\n$2" | sort -V | head -n1)" ] +} + +function verlt() { + [ "$1" = "$2" ] && return 1 || verlte $1 $2 +} + +function check_version() { + if [[ "$1" == "terraform" ]]; then + tmp_dir=$(mktemp -d) + cd ${tmp_dir} + set +o pipefail # terraform fails on command piping when not last version + cur_ver=$(terraform version | head -n 1 | cut -d' ' -f2) + set -o pipefail + cur_ver=${cur_ver#"v"} + cd - > /dev/null + rm -fr ${tmp_dir} + req_ver=$(grep required_version README.md | awk '{print $4}') + req_ver=${req_ver%'"'} + elif [[ "$1" == "terraform-docs" ]]; then + if [[ "$(grep terraform-docs README.md)" =~ [[:space:]]v([0-9]*\.[0-9]*\.[0-9]*).*\. ]]; then + req_ver="${BASH_REMATCH[1]}" + else + echo "impossible to retrieve required terraform-docs version from README" + exit 3 + fi + cur_ver=$(terraform-docs --version) + else + return 0 + fi + if ! verlte $req_ver $cur_ver; then + echo "This requires at least version ${req_ver} of $1, please upgrade (current version is ${cur_ver})" + exit 2 + fi +} + +for cmd in terraform terraform-docs terraform-config-inspect jq; do + echo -e "\t- Check command \"$cmd\" exists and in right version" + check_command $cmd + check_version $cmd +done diff --git a/.terraform/modules/datadog-monitors-system-generic/scripts/10_update_output.sh b/.terraform/modules/datadog-monitors-system-generic/scripts/10_update_output.sh new file mode 100755 index 0000000..2a55c24 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/scripts/10_update_output.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +source "$(dirname $0)/utils.sh" +init +if [ "${REPO}" != "monitors" ]; then + # Run this script only for monitors repo + exit 0 +fi +echo "Generate terraform outputs.tf files for every monitors modules" + +# loop over every modules +for module in $(browse_modules "$(get_scope ${1:-})" "${REPO}-*.tf"); do + echo -e "\t- Generate outputs.tf for module: ${module}" + cd ${module} + # empty outputs + > outputs.tf + # gather a information line splitted with "|" for every monitor + for row in $(terraform-config-inspect --json | jq -c -r '.managed_resources | map([.name] | join("|")) | join("\n")'); do + # split line for each info one variable + IFS='|' read monitor type < <(echo $row) + # create output block for current monitor + cat >> outputs.tf <> /dev/null +done diff --git a/.terraform/modules/datadog-monitors-system-generic/scripts/20_update_global_readme.sh b/.terraform/modules/datadog-monitors-system-generic/scripts/20_update_global_readme.sh new file mode 100755 index 0000000..3f7e538 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/scripts/20_update_global_readme.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +source "$(dirname $0)/utils.sh" +init +echo "Update global README.md" + +# only keep current README from begining to "[Monitors/Integrations] summary" section (delete list) +sed -i "/## ${REPO^} summary/q" README.md +# add a newline after listing section +echo >> README.md +# loop over path of modules tree +for path in $(find -mindepth 1 -type d ! -path '*/.*' ! -path './scripts*' ! -path './common/module' -print | sort -fdbi); do + # split path in directories + directories=($(list_dirs $path)) + # loop over directories in path + for i in $(seq 1 $((${#directories[@]}-1))); do + ## add tabulation for every subdirectory + echo -en "\t" >> README.md + done + # add link to list of modules + echo -en "- [$(basename ${path})](https://github.com/claranet/terraform-datadog-${REPO}/tree/master/" >> README.md + # add path to link + for directory in "${directories[@]}"; do + echo -en "${directory}/" >> README.md + done + # end of markdown link + echo ")" >> README.md +done diff --git a/.terraform/modules/datadog-monitors-system-generic/scripts/20_update_modules_readmes.sh b/.terraform/modules/datadog-monitors-system-generic/scripts/20_update_modules_readmes.sh new file mode 100755 index 0000000..64d34ff --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/scripts/20_update_modules_readmes.sh @@ -0,0 +1,119 @@ +#!/bin/bash + +source "$(dirname $0)/utils.sh" +init +echo "Update README.md for every ${REPO} modules" + +# this is the pattern from where custom information is saved to be restored +PATTERN_DOC="Related documentation" + +# loop over every modules +for module in $(browse_modules "$(get_scope ${1:-})" "${REPO}-*.tf"); do + echo -e "\t- Generate README.md for module: ${module}" + cd ${module} + EXIST=0 + if [ -f README.md ]; then + mv README.md README.md.bak + EXIST=1 + fi + # module name from path + module_space=$(list_dirs ${module}) + # module name with space as separator + module_upper=${module_space^^} + # module name with dash as separator + module_dash=${module_space//[ ]/-} + # module name with slash as separator + module_slash=${module_space//[ ]/\/} + + # (re)generate README from scratch + cat < README.md +# ${module_upper} DataDog ${REPO} + +## How to use this module + +\`\`\`hcl +module "datadog-${REPO}-${module_dash}" { + source = "claranet/${REPO}/datadog//${module_slash}" + version = "{revision}" +EOF + + append="" + list="" + last_argument="version" + if [ "${REPO}" == "monitors" ]; then + cat <> README.md + + environment = var.environment + message = module.datadog-message-alerting.alerting-message +EOF + last_argument="message" + set +e + IFS='' read -r -d '' append < /dev/null + cd - >> /dev/null +done diff --git a/.terraform/modules/datadog-monitors-system-generic/scripts/30_update_module.sh b/.terraform/modules/datadog-monitors-system-generic/scripts/30_update_module.sh new file mode 100755 index 0000000..7caa669 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/scripts/30_update_module.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +source "$(dirname $0)/utils.sh" +init +if [ "${REPO}" != "monitors" ]; then + # Run this script only for monitors repo + exit 0 +fi +echo "Generate outputs.tf files when does not exist for every monitors modules" +root=$(basename ${PWD}) + +# loop over every modules +for module in $(browse_modules "$(get_scope ${1:-})" "${REPO}-*.tf"); do + cd ${module} + # get name of the monitors set directory + resource="$(basename ${module})" + # if modules.tf does not exist AND if this set respect our tagging convention + if ! [ -f modules.tf ] && grep -q filter_tags_use_defaults inputs.tf; then + echo -e "\t- Generate modules.tf for module: ${module}" + relative="" + current="${PWD}" + # iterate on path until we go back to root + while [[ "$(basename $current)" != "$root" ]]; do + # for each iteration add "../" to generate relative path + relative="${relative}../" + # remove last directory from current path + current="$(dirname $current)" + done + # add the filter tags module + cat > modules.tf <> /dev/null +done diff --git a/.terraform/modules/datadog-monitors-system-generic/scripts/90_best_practices.sh b/.terraform/modules/datadog-monitors-system-generic/scripts/90_best_practices.sh new file mode 100755 index 0000000..4dc2ddc --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/scripts/90_best_practices.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +source "$(dirname $0)/utils.sh" +init +if [ "${REPO}" != "monitors" ]; then + # Run this script only for monitors repo + exit 0 +fi +echo "Check best practices respect" + +echo -e "\t- Check only one notify_no_data set to true per module" +# loop over every modules +for module in $(browse_modules "$(get_scope ${1:-})" "${REPO}-*.tf"); do + # check if there is more than 1 notify_no_data not set to false. + # here the risk to check is the possible "true" value while this could lead the duplicated no data alerts. + # every metrics from one module come from the same source so this does not make sens to check no data for multiple monitors in the same module. + if [[ $(cat ${module}/monitors-*.tf | grep 'notify_no_data[[:space:]]*=' | grep -cv '=[[:space:]]*false') -gt 1 ]]; then + echo "More than one notify_no_data not set to \"false\" in $module" + exit 1 + fi +done diff --git a/.terraform/modules/datadog-monitors-system-generic/scripts/99_terraform.sh b/.terraform/modules/datadog-monitors-system-generic/scripts/99_terraform.sh new file mode 100755 index 0000000..b4959ca --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/scripts/99_terraform.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +source "$(dirname $0)/utils.sh" +init +echo "Check terraform CI" + +# Clean when exit +err() { + rm -f "${module}/tmp.tf" +} +trap 'err $LINENO' ERR TERM EXIT INT + +provider_version=$(grep -m1 ^[[:space:]]*version[[:space:]]= README.md | awk '{print $3}') + +# loop over every modules +for module in $(browse_modules "$(get_scope ${1:-})" 'inputs.tf'); do + echo -e "\t- Terraform validate on module: ${module}" + if [[ ${module} != ./common/* ]]; then + cat < ${module}/tmp.tf +provider "datadog" { + api_key = var.datadog_api_key + app_key = var.datadog_app_key +} + +variable "datadog_api_key" { + type = string + default = "xxx" +} + +variable "datadog_app_key" { + type = string + default = "yyy" +} + +EOF + + if ! [ -f ${module}/versions.tf ]; then + cp ./common/module/versions.tf ${module}/ + fi + fi + + if [ -f ${module}/test.tf.ci ]; then + cat ${module}/test.tf.ci >> ${module}/tmp.tf + fi + terraform -chdir=${module} init > /tmp/null + terraform -chdir=${module} validate + rm -f ${module}/tmp.tf +done + +echo -e "\t- Terraform fmt recursive" +terraform fmt -recursive + diff --git a/.terraform/modules/datadog-monitors-system-generic/scripts/README.md b/.terraform/modules/datadog-monitors-system-generic/scripts/README.md new file mode 100755 index 0000000..25e4d00 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/scripts/README.md @@ -0,0 +1,65 @@ +# Datadog scripts + +## Summary + +This repository contains a `scripts` directory where there are multiple scripts helping to different things: + +- help and automate for some boring and repetitive tasks. +- keep everything up to date and warn if you forget. +- compliant checks and ensure best practices are respected. +- code validation for continuous integration. + +## Structure + +There are two kinds of scripts naming: + +- `[0-9][0-9]_script_name.sh`: will be automatically run by `auto_update.sh` wrapper. +- `script_name.sh`: should be run manually. + +Here is a list of scripts and their purpose: + +- `auto_update.sh`: is the most important and the one the must used. It is a simple wrapper which will calls every other `[0-9][0-9]*` scripts. + - It should be run by contributor after every change. + - The CI will also run it and it will fail if it detects any change compared to commit. + - "Children" scripts could be run individually if you know exactly what you need to update after a change. + - This script all "children" scripts takes one optional parameter to limit execution to a specific sub path. Else this will run on all directories. +- `00_requirements.sh`: check some requirements like `terraform` command exists before run other scripts. +- `10_update_output.sh`: will generate and update all `outputs.tf`. +- `20_update_global_readme.sh`: will update the main `README.md` file and generate the list of all modules browsing the repository. +- `20_update_modules_readmes.sh`: will create and update `README.md` for each module. It will save all manual changes below `## Related documentation` section. +- `30_update_module.sh`: will create `modules.tf` file per module when does not exist. +- `90_best_practices.sh`: will check compliance and best practices respect. +- `99_terraform.sh`: terraform CI (init & validate only while auto apply is done in another pipeline). +- `utils.sh`: contains useful functions common to multiple scripts. It is not attended to be run. +- `changelog.sh`: helper script to release a new version. + - generate and update `CHANGELOG.md` file from git history. + - filter to list only "done" issues from JIRA. + - close all issues on JIRA. + - fix version for all issues on JIRA. + - create release for current version on JIRA. + +## Usage + +First, you need to retrieve `scripts` repository by cloning submodules: + +``` +git submodule update --init +``` + +After any change on this repo, you will need to run the `./scripts/auto_update.sh [PATH_TO_MODULE]` command to make sure all is up to date otherwise the CI pipeline will fail. +The parameter is optional and it will limit the scripts execution on a specific path on the repository. + +On linux system it is possible to run the script directly while `terraform`, `terraform-docs`, `terraform-config-inspect`, `jq` commands are available in your `PATH`. +Otherwise you can use [the same docker image as the CI](https://hub.docker.com/r/claranet/terraform-ci) on every other platforms. + + +``` +# if you already pulled the container once, you will need to update it +$ docker pull claranet/terraform-ci +# then just need to run the script of your choice with optional path parameter or not +$ docker run --rm -v "$PWD:/work" claranet/terraform-ci /work/scripts/auto_update.sh +# else if you run docker in version >= 19.09 (or nightly builds) so you can do it both in one command +$ docker run --pull=always --rm -v "$PWD:/work" claranet/terraform-ci /work/scripts/auto_update.sh +# it is also possible to run the scripts in debug in case of silent fail +$ docker run -e GITLAB_CI=true --rm -v "$PWD:/work" claranet/terraform-ci /work/scripts/auto_update.sh +``` diff --git a/.terraform/modules/datadog-monitors-system-generic/scripts/auto_update.sh b/.terraform/modules/datadog-monitors-system-generic/scripts/auto_update.sh new file mode 100755 index 0000000..3371f04 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/scripts/auto_update.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +source "$(dirname $0)/utils.sh" +init scripts + +for script in [0-9][0-9]_*.sh; do + ./${script} "$(get_scope ${1:-})" +done diff --git a/.terraform/modules/datadog-monitors-system-generic/scripts/changelog.sh b/.terraform/modules/datadog-monitors-system-generic/scripts/changelog.sh new file mode 100755 index 0000000..3a8e03f --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/scripts/changelog.sh @@ -0,0 +1,145 @@ +#/bin/bash +set -euo pipefail + +source "$(dirname $0)/utils.sh" +goto_root + +## Check parameters and environment variables +# PARAMETER: The next version to release (i.e. v3.0.0) +# JIRA_API_TOKEN: the user api token to login jira +# JIRA_LOGIN: the user email to login on jira + +if [ $# -eq 0 ]; then + echo "Target tag is required as parameter" + exit 1 +fi + +if [ -z ${JIRA_API_TOKEN:-} ]; then + echo "Environment variable JIRA_API_TOKEN needs to be defined: https://confluence.atlassian.com/cloud/api-tokens-938839638.html" + exit 2 +fi + +if [ -z ${JIRA_LOGIN:-} ]; then + echo "Environment variable JIRA_LOGIN needs to be defined: jira user email" + exit 3 +fi + +if ! command -v jira >/dev/null; then + echo "go-jira command is required: https://github.com/go-jira/jira#install" +fi + +TAG_TARGET=$1 +TAG_SOURCE=${TAG_SOURCE:-$(git describe --tags --abbrev=0)} +JIRA_ENDPOINT=${JIRA_ENDPOINT:-https://claranet-morea.atlassian.net} +JIRA_STATUS=${JIRA_STATUS:-Done Closed} +SAVEIFS=$IFS +IFS=$(echo -en "\n\b") +TMP=$(mktemp -d) + +# Clean when exit +err() { + rm -fr ${TMP} + IFS=$SAVEIFS +} +trap 'err $LINENO' ERR TERM EXIT INT + +# Create the go-jira template with issue, status and summary as CSV +mkdir -p ${HOME}/.jira.d/templates +cat > ${HOME}/.jira.d/templates/changelog < ${HOME}/.jira.d/templates/versions <> ${HOME}/.jira.d/templates/fixversion < $TMP_ISSUES + +TMP_INFO_ISSUES=${TMP}/info-issues.txt +for issue in $(cat $TMP_ISSUES); do + # retrieve jira information from go-jira template + jira --endpoint=${JIRA_ENDPOINT} --login=${JIRA_LOGIN} view $issue --template=changelog +done | sort > $TMP_INFO_ISSUES + +TMP_TREATED_ISSUES=${TMP}/treated-issues.txt +TMP_CHANGELOG=${TMP}/changelog.md +# init changelog for next version +echo -e "\n# $TAG_TARGET ($(LANG=eng date +"%B %d, %Y"))" >> $TMP_CHANGELOG +for line in $(cat $TMP_INFO_ISSUES); do + # retrieve jira information from go-jira template + IFS=';' read -r type issue status summary <<< $line + # Ignore if issue is not in required status + if ! [[ "$JIRA_STATUS" == *"$status"* ]]; then + echo "Issue $issue with status \"$status\" not in [$JIRA_STATUS] ($summary)" + read -p 'Would you like to transition issue to "Done" status ? if no, the issue will be ignored ([y]/n): ' -r answer + if [[ "$answer" != "n" ]]; then + if [[ "$status" == "Qualif" ]]; then + jira --endpoint=${JIRA_ENDPOINT} --login=${JIRA_LOGIN} transition "Approve" $issue --noedit > /dev/null + status="To Do" + fi + if [[ "$status" == "To Do" ]]; then + jira --endpoint=${JIRA_ENDPOINT} --login=${JIRA_LOGIN} transition "In Progress" $issue --noedit > /dev/null + status="In Progress" + fi + if [[ "$status" == "In Progress" ]]; then + jira --endpoint=${JIRA_ENDPOINT} --login=${JIRA_LOGIN} transition "Review" $issue --noedit > /dev/null + status="In Review" + fi + if [[ "$status" == "In Review" ]]; then + jira --endpoint=${JIRA_ENDPOINT} --login=${JIRA_LOGIN} transition "Done" $issue --noedit > /dev/null + fi + fi + fi + # add line for type only once + if ! grep -q "^## $type" $TMP_CHANGELOG; then + echo -e "\n## $type\n" >> $TMP_CHANGELOG + fi + # add jira issue line to changelog + echo "* [[$issue](${JIRA_ENDPOINT}/browse/${issue})] - $summary" >> $TMP_CHANGELOG + echo $issue >> $TMP_TREATED_ISSUES +done + +cat $TMP_CHANGELOG +# Ask for confirmation to update changelog +read -p 'Update CHANGELOG.md with this ? (y/[n]): ' -r answer +if [[ "$answer" == "y" ]]; then + separator='\n' + # Remove target tag changelog if already exist + if grep -q $TAG_TARGET CHANGELOG.md; then + prev_tag=$(grep '^# v' CHANGELOG.md | sed -n 2p) + sed -i "/${prev_tag}/,\$!d" CHANGELOG.md + separator="${separator}\n" + fi + # Add target tag changelog to final changelog + echo -e "$(cat $TMP_CHANGELOG)${separator}$(cat CHANGELOG.md)" > CHANGELOG.md +fi + +read -p "Close all issues and fix version $TAG_TARGET ? (y/[n]): " -r answer +if [[ "$answer" == "y" ]]; then + # Create version if does not exists + one_issue=$(head -n 1 $TMP_TREATED_ISSUES) + auth_header=$(printf "${JIRA_LOGIN}:${JIRA_API_TOKEN}" | base64) + if ! jira --endpoint=${JIRA_ENDPOINT} --login=${JIRA_LOGIN} editmeta $one_issue --template=versions | grep -q $TAG_TARGET; then + curl -H "Authorization: Basic $auth_header" -H "Content-Type: application/json" -X POST -d "{\"name\": \"${TAG_TARGET}\",\"userReleaseDate\": \"$(echo -n $(LANG=eng date +'%-d/%b/%Y'))\",\"project\": \"$(echo -n $one_issue | cut -d'-' -f1)\",\"archived\": false,\"released\": true}" ${JIRA_ENDPOINT}/rest/api/latest/version + fi + for issue in $(cat $TMP_TREATED_ISSUES); do + jira --endpoint=${JIRA_ENDPOINT} --login=${JIRA_LOGIN} transition "Close" $issue --noedit > /dev/null 2>&1 && echo "OK $issue closed" || echo "OK $issue already closed" + jira --endpoint=${JIRA_ENDPOINT} --login=${JIRA_LOGIN} edit $issue --template=fixversion --override fixVersions=${TAG_TARGET} --noedit > /dev/null && echo "OK $issue fix version $TAG_TARGET" + done +fi diff --git a/.terraform/modules/datadog-monitors-system-generic/scripts/utils.sh b/.terraform/modules/datadog-monitors-system-generic/scripts/utils.sh new file mode 100755 index 0000000..a419cb1 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/scripts/utils.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +function goto_root() { + script_dir=$(dirname $0) + if [[ "$script_dir" == "." ]]; then + cd .. + else + cd "$(dirname $script_dir)" + fi +} + +function init() { + set -euo pipefail + if [[ ${GITLAB_CI:-} == "true" ]]; then + set -x + fi + # MON-478 fix sort order behavior on case + export LC_COLLATE=C + goto_root + if ! [ -z ${1:-} ]; then + cd "$1" + fi + REPO="integrations" + if head -n1 ./README.md | grep -q -i monitors; then + REPO="monitors" + fi +} + +function get_scope() { + TO_PARSE="./" + if [ ! -z ${1+x} ] && [ $1 != "." ]; then + TO_PARSE="$1" + fi + if [[ $TO_PARSE != ./* ]]; then + TO_PARSE="./${TO_PARSE}" + fi + echo $TO_PARSE +} + +function list_dirs() { + echo ${1} | awk -F '/' '{$1=""; print $0}' | cut -c 2- +} + +function browse_modules() { + find "$1" -name "$2" -exec dirname "{}" \; | sort -fdbiu +} + +function get_name() { + regex='^[[:space:]]+name[[:space:]]+=[[:space:]]+"\$.*\[.*\][[:space:]]+(.*)"$' + if [[ "${1}" =~ ${regex} ]]; then + name="${BASH_REMATCH[1]}" + else + echo "Error: impossible to parse monitor name" + return 42 + fi + if [[ "${name}" =~ ^(.*)[[:space:]]\{\{#is_alert\}\}.*$ ]]; then + name="${BASH_REMATCH[1]}" + fi + echo $name + return 0 +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/system/generic/README.md b/.terraform/modules/datadog-monitors-system-generic/system/generic/README.md new file mode 100755 index 0000000..0c4aca4 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/system/generic/README.md @@ -0,0 +1,134 @@ +# SYSTEM GENERIC DataDog monitors + +## How to use this module + +```hcl +module "datadog-monitors-system-generic" { + source = "claranet/monitors/datadog//system/generic" + version = "{revision}" + + environment = var.environment + message = module.datadog-message-alerting.alerting-message + + memory_message = "${module.datadog-message-alerting-bh-only.alerting-message}" +} + +``` + +## Purpose + +Creates DataDog monitors with the following checks: + +- CPU load 5 ratio +- CPU usage +- Disk inodes usage +- Disk space usage +- Disk Space usage forecast +- Usable Memory + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | +| [filter-tags-disk](#module\_filter-tags-disk) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.cpu](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.disk_inodes](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.disk_space](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.disk_space_forecast](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.load](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | +| [datadog_monitor.memory](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cpu\_enabled](#input\_cpu\_enabled) | Flag to enable CPU high monitor | `string` | `"true"` | no | +| [cpu\_extra\_tags](#input\_cpu\_extra\_tags) | Extra tags for CPU high monitor | `list(string)` | `[]` | no | +| [cpu\_message](#input\_cpu\_message) | Custom message for CPU high monitor | `string` | `""` | no | +| [cpu\_threshold\_critical](#input\_cpu\_threshold\_critical) | CPU high critical threshold | `number` | `90` | no | +| [cpu\_threshold\_warning](#input\_cpu\_threshold\_warning) | CPU high warning threshold | `number` | `85` | no | +| [cpu\_time\_aggregator](#input\_cpu\_time\_aggregator) | Monitor aggregator for CPU high [available values: min, max or avg] | `string` | `"min"` | no | +| [cpu\_timeframe](#input\_cpu\_timeframe) | Monitor timeframe for CPU high [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_1h"` | no | +| [disk\_inodes\_enabled](#input\_disk\_inodes\_enabled) | Flag to enable Free disk inodes monitor | `string` | `"true"` | no | +| [disk\_inodes\_extra\_tags](#input\_disk\_inodes\_extra\_tags) | Extra tags for Free disk inodes monitor | `list(string)` | `[]` | no | +| [disk\_inodes\_message](#input\_disk\_inodes\_message) | Custom message for Free disk inodes monitor | `string` | `""` | no | +| [disk\_inodes\_threshold\_critical](#input\_disk\_inodes\_threshold\_critical) | Free disk space critical threshold | `number` | `95` | no | +| [disk\_inodes\_threshold\_warning](#input\_disk\_inodes\_threshold\_warning) | Free disk space warning threshold | `number` | `90` | no | +| [disk\_inodes\_time\_aggregator](#input\_disk\_inodes\_time\_aggregator) | Monitor aggregator for Free disk inodes [available values: min, max or avg] | `string` | `"min"` | no | +| [disk\_inodes\_timeframe](#input\_disk\_inodes\_timeframe) | Monitor timeframe for Free disk inodes [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [disk\_space\_enabled](#input\_disk\_space\_enabled) | Flag to enable Free diskspace monitor | `string` | `"true"` | no | +| [disk\_space\_extra\_tags](#input\_disk\_space\_extra\_tags) | Extra tags for Free diskspace monitor | `list(string)` | `[]` | no | +| [disk\_space\_forecast\_algorithm](#input\_disk\_space\_forecast\_algorithm) | Algorithm for the Free diskspace Forecast monitor [available values: `linear` or `seasonal`] | `string` | `"linear"` | no | +| [disk\_space\_forecast\_deviations](#input\_disk\_space\_forecast\_deviations) | Deviations for the Free diskspace Forecast monitor [available values: `1`, `2`, `3`, `4` or `5`] | `string` | `1` | no | +| [disk\_space\_forecast\_enabled](#input\_disk\_space\_forecast\_enabled) | Flag to enable Free diskspace forecast monitor | `string` | `"true"` | no | +| [disk\_space\_forecast\_extra\_tags](#input\_disk\_space\_forecast\_extra\_tags) | Extra tags for Free diskspace forecast monitor | `list(string)` | `[]` | no | +| [disk\_space\_forecast\_interval](#input\_disk\_space\_forecast\_interval) | Interval for the Free diskspace Forecast monitor [available values: `30m`, `60m` or `120m`] | `string` | `"60m"` | no | +| [disk\_space\_forecast\_linear\_history](#input\_disk\_space\_forecast\_linear\_history) | History for the Free diskspace Forecast monitor [available values: `12h`, `#d` (1, 2, or 3), `#w` (1, or 2) or `#mo` (1, 2 or 3)] | `string` | `"1w"` | no | +| [disk\_space\_forecast\_linear\_model](#input\_disk\_space\_forecast\_linear\_model) | Model for the Free diskspace Forecast monitor [available values: `default`, `simple` or `reactive`] | `string` | `"default"` | no | +| [disk\_space\_forecast\_message](#input\_disk\_space\_forecast\_message) | Custom message for Free diskspace forecast monitor | `string` | `""` | no | +| [disk\_space\_forecast\_seasonal\_seasonality](#input\_disk\_space\_forecast\_seasonal\_seasonality) | Seasonality for the Free diskspace Forecast monitor | `string` | `"weekly"` | no | +| [disk\_space\_forecast\_threshold\_critical](#input\_disk\_space\_forecast\_threshold\_critical) | Free disk space forecast critical threshold | `number` | `80` | no | +| [disk\_space\_forecast\_threshold\_critical\_recovery](#input\_disk\_space\_forecast\_threshold\_critical\_recovery) | Free disk space forecast recovery threshold | `number` | `72` | no | +| [disk\_space\_forecast\_time\_aggregator](#input\_disk\_space\_forecast\_time\_aggregator) | Monitor aggregator for Free diskspace forecast [available values: min, max or avg] | `string` | `"max"` | no | +| [disk\_space\_forecast\_timeframe](#input\_disk\_space\_forecast\_timeframe) | Monitor timeframe for Free diskspace forecast [available values: `next_12h`, `next_#d` (1, 2, or 3), `next_#w` (1 or 2) or `next_#mo` (1, 2 or 3)] | `string` | `"next_1w"` | no | +| [disk\_space\_message](#input\_disk\_space\_message) | Custom message for Free diskspace monitor | `string` | `""` | no | +| [disk\_space\_threshold\_critical](#input\_disk\_space\_threshold\_critical) | Free disk space critical threshold | `number` | `90` | no | +| [disk\_space\_threshold\_warning](#input\_disk\_space\_threshold\_warning) | Free disk space warning threshold | `number` | `80` | no | +| [disk\_space\_time\_aggregator](#input\_disk\_space\_time\_aggregator) | Monitor aggregator for Free diskspace [available values: min, max or avg] | `string` | `"max"` | no | +| [disk\_space\_timeframe](#input\_disk\_space\_timeframe) | Monitor timeframe for Free diskspace [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [load\_enabled](#input\_load\_enabled) | Flag to enable CPU load ratio monitor | `string` | `"true"` | no | +| [load\_extra\_tags](#input\_load\_extra\_tags) | Extra tags for CPU load ratio monitor | `list(string)` | `[]` | no | +| [load\_message](#input\_load\_message) | Custom message for CPU load ratio monitor | `string` | `""` | no | +| [load\_threshold\_critical](#input\_load\_threshold\_critical) | CPU load ratio critical threshold | `number` | `2.5` | no | +| [load\_threshold\_warning](#input\_load\_threshold\_warning) | CPU load ratio warning threshold | `number` | `2` | no | +| [load\_time\_aggregator](#input\_load\_time\_aggregator) | Monitor aggregator for CPU load ratio [available values: min, max or avg] | `string` | `"min"` | no | +| [load\_timeframe](#input\_load\_timeframe) | Monitor timeframe for CPU load ratio [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_30m"` | no | +| [memory\_enabled](#input\_memory\_enabled) | Flag to enable Free memory monitor | `string` | `"true"` | no | +| [memory\_extra\_tags](#input\_memory\_extra\_tags) | Extra tags for Free memory monitor | `list(string)` | `[]` | no | +| [memory\_message](#input\_memory\_message) | Mandatory message for Free memory monitor to avoid NBH alerting by default | `string` | n/a | yes | +| [memory\_threshold\_critical](#input\_memory\_threshold\_critical) | Free disk space critical threshold | `number` | `5` | no | +| [memory\_threshold\_warning](#input\_memory\_threshold\_warning) | Free disk space warning threshold | `number` | `10` | no | +| [memory\_time\_aggregator](#input\_memory\_time\_aggregator) | Monitor aggregator for Free memory [available values: min, max or avg] | `string` | `"max"` | no | +| [memory\_timeframe](#input\_memory\_timeframe) | Monitor timeframe for Free memory [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`] | `string` | `"last_5m"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [cpu\_id](#output\_cpu\_id) | id for monitor cpu | +| [disk\_inodes\_id](#output\_disk\_inodes\_id) | id for monitor disk\_inodes | +| [disk\_space\_forecast\_id](#output\_disk\_space\_forecast\_id) | id for monitor disk\_space\_forecast | +| [disk\_space\_id](#output\_disk\_space\_id) | id for monitor disk\_space | +| [load\_id](#output\_load\_id) | id for monitor load | +| [memory\_id](#output\_memory\_id) | id for monitor memory | +## Related documentation + +DataDog documentation: diff --git a/.terraform/modules/datadog-monitors-system-generic/system/generic/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/system/generic/inputs.tf new file mode 100755 index 0000000..538fc75 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/system/generic/inputs.tf @@ -0,0 +1,323 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# System generic specific + +variable "cpu_enabled" { + description = "Flag to enable CPU high monitor" + type = string + default = "true" +} + +variable "cpu_extra_tags" { + description = "Extra tags for CPU high monitor" + type = list(string) + default = [] +} + +variable "cpu_message" { + description = "Custom message for CPU high monitor" + type = string + default = "" +} + +variable "cpu_time_aggregator" { + description = "Monitor aggregator for CPU high [available values: min, max or avg]" + type = string + default = "min" +} + +variable "cpu_timeframe" { + description = "Monitor timeframe for CPU high [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_1h" +} + +variable "cpu_threshold_warning" { + description = "CPU high warning threshold" + default = 85 +} + +variable "cpu_threshold_critical" { + description = "CPU high critical threshold" + default = 90 +} + +variable "load_enabled" { + description = "Flag to enable CPU load ratio monitor" + type = string + default = "true" +} + +variable "load_extra_tags" { + description = "Extra tags for CPU load ratio monitor" + type = list(string) + default = [] +} + +variable "load_message" { + description = "Custom message for CPU load ratio monitor" + type = string + default = "" +} + +variable "load_time_aggregator" { + description = "Monitor aggregator for CPU load ratio [available values: min, max or avg]" + type = string + default = "min" +} + +variable "load_timeframe" { + description = "Monitor timeframe for CPU load ratio [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_30m" +} + +variable "load_threshold_warning" { + description = "CPU load ratio warning threshold" + default = 2 +} + +variable "load_threshold_critical" { + description = "CPU load ratio critical threshold" + default = 2.5 +} + +variable "disk_space_enabled" { + description = "Flag to enable Free diskspace monitor" + type = string + default = "true" +} + +variable "disk_space_extra_tags" { + description = "Extra tags for Free diskspace monitor" + type = list(string) + default = [] +} + +variable "disk_space_message" { + description = "Custom message for Free diskspace monitor" + type = string + default = "" +} + +variable "disk_space_time_aggregator" { + description = "Monitor aggregator for Free diskspace [available values: min, max or avg]" + type = string + default = "max" +} + +variable "disk_space_timeframe" { + description = "Monitor timeframe for Free diskspace [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "disk_space_threshold_warning" { + description = "Free disk space warning threshold" + default = 80 +} + +variable "disk_space_threshold_critical" { + description = "Free disk space critical threshold" + default = 90 +} + +variable "disk_space_forecast_enabled" { + description = "Flag to enable Free diskspace forecast monitor" + type = string + default = "true" +} + +variable "disk_space_forecast_extra_tags" { + description = "Extra tags for Free diskspace forecast monitor" + type = list(string) + default = [] +} + +variable "disk_space_forecast_message" { + description = "Custom message for Free diskspace forecast monitor" + type = string + default = "" +} + +variable "disk_space_forecast_time_aggregator" { + description = "Monitor aggregator for Free diskspace forecast [available values: min, max or avg]" + type = string + default = "max" +} + +variable "disk_space_forecast_timeframe" { + description = "Monitor timeframe for Free diskspace forecast [available values: `next_12h`, `next_#d` (1, 2, or 3), `next_#w` (1 or 2) or `next_#mo` (1, 2 or 3)]" + type = string + default = "next_1w" +} + +variable "disk_space_forecast_algorithm" { + description = "Algorithm for the Free diskspace Forecast monitor [available values: `linear` or `seasonal`]" + type = string + default = "linear" +} + +variable "disk_space_forecast_deviations" { + description = "Deviations for the Free diskspace Forecast monitor [available values: `1`, `2`, `3`, `4` or `5`]" + type = string + default = 1 +} + +variable "disk_space_forecast_interval" { + description = "Interval for the Free diskspace Forecast monitor [available values: `30m`, `60m` or `120m`]" + type = string + default = "60m" +} + +variable "disk_space_forecast_linear_history" { + description = "History for the Free diskspace Forecast monitor [available values: `12h`, `#d` (1, 2, or 3), `#w` (1, or 2) or `#mo` (1, 2 or 3)]" + type = string + default = "1w" +} + +variable "disk_space_forecast_linear_model" { + description = "Model for the Free diskspace Forecast monitor [available values: `default`, `simple` or `reactive`]" + type = string + default = "default" +} + +variable "disk_space_forecast_seasonal_seasonality" { + description = "Seasonality for the Free diskspace Forecast monitor" + type = string + default = "weekly" +} + +variable "disk_space_forecast_threshold_critical_recovery" { + description = "Free disk space forecast recovery threshold" + default = 72 +} + +variable "disk_space_forecast_threshold_critical" { + description = "Free disk space forecast critical threshold" + default = 80 +} + +variable "disk_inodes_enabled" { + description = "Flag to enable Free disk inodes monitor" + type = string + default = "true" +} + +variable "disk_inodes_extra_tags" { + description = "Extra tags for Free disk inodes monitor" + type = list(string) + default = [] +} + +variable "disk_inodes_message" { + description = "Custom message for Free disk inodes monitor" + type = string + default = "" +} + +variable "disk_inodes_time_aggregator" { + description = "Monitor aggregator for Free disk inodes [available values: min, max or avg]" + type = string + default = "min" +} + +variable "disk_inodes_timeframe" { + description = "Monitor timeframe for Free disk inodes [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "disk_inodes_threshold_warning" { + description = "Free disk space warning threshold" + default = 90 +} + +variable "disk_inodes_threshold_critical" { + description = "Free disk space critical threshold" + default = 95 +} + +variable "memory_enabled" { + description = "Flag to enable Free memory monitor" + type = string + default = "true" +} + +variable "memory_extra_tags" { + description = "Extra tags for Free memory monitor" + type = list(string) + default = [] +} + +variable "memory_message" { + description = "Mandatory message for Free memory monitor to avoid NBH alerting by default" + type = string +} + +variable "memory_time_aggregator" { + description = "Monitor aggregator for Free memory [available values: min, max or avg]" + type = string + default = "max" +} + +variable "memory_timeframe" { + description = "Monitor timeframe for Free memory [available values: `last_#m` (1, 5, 10, 15, or 30), `last_#h` (1, 2, or 4), or `last_1d`]" + type = string + default = "last_5m" +} + +variable "memory_threshold_warning" { + description = "Free disk space warning threshold" + default = 10 +} + +variable "memory_threshold_critical" { + description = "Free disk space critical threshold" + default = 5 +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/system/generic/modules.tf b/.terraform/modules/datadog-monitors-system-generic/system/generic/modules.tf new file mode 100755 index 0000000..fc2e056 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/system/generic/modules.tf @@ -0,0 +1,21 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "system" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + +module "filter-tags-disk" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "system" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded + extra_tags = ["dd_disk:enabled"] +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/system/generic/monitors-system.tf b/.terraform/modules/datadog-monitors-system-generic/system/generic/monitors-system.tf new file mode 100755 index 0000000..0440aaa --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/system/generic/monitors-system.tf @@ -0,0 +1,183 @@ +resource "datadog_monitor" "cpu" { + count = var.cpu_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] CPU usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.cpu_message, var.message) + type = "query alert" + + query = < ${var.cpu_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.cpu_threshold_warning + critical = var.cpu_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:system", "provider:system-check", "resource:generic", "team:claranet", "created-by:terraform"], var.cpu_extra_tags) +} + +resource "datadog_monitor" "load" { + count = var.load_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] CPU load 5 ratio {{#is_alert}}{{{comparator}}} {{threshold}} ({{value}}){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}} ({{value}}){{/is_warning}}" + message = coalesce(var.load_message, var.message) + type = "query alert" + + query = < ${var.load_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.load_threshold_warning + critical = var.load_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:system", "provider:system-core", "resource:generic", "team:claranet", "created-by:terraform"], var.load_extra_tags) +} + +resource "datadog_monitor" "disk_space" { + count = var.disk_space_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Disk space usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.disk_space_message, var.message) + type = "query alert" + + query = < ${var.disk_space_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.disk_space_threshold_warning + critical = var.disk_space_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:system", "provider:disk", "resource:generic", "team:claranet", "created-by:terraform"], var.disk_space_extra_tags) +} + +resource "datadog_monitor" "disk_space_forecast" { + count = var.disk_space_forecast_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Disk Space usage could reach {{#is_alert}}{{threshold}}%%{{/is_alert}} in a near future" + message = coalesce(var.disk_space_forecast_message, var.message) + type = "query alert" + + query = <= ${var.disk_space_forecast_threshold_critical} +EOQ + + monitor_thresholds { + critical_recovery = var.disk_space_forecast_threshold_critical_recovery + critical = var.disk_space_forecast_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_audit = false + locked = false + timeout_h = 0 + include_tags = true + require_full_window = true + notify_no_data = false + renotify_interval = 0 + + tags = concat(["env:${var.environment}", "type:system", "provider:disk", "resource:generic", "team:claranet", "created-by:terraform"], var.disk_space_forecast_extra_tags) +} + +resource "datadog_monitor" "disk_inodes" { + count = var.disk_inodes_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Disk inodes usage {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = coalesce(var.disk_inodes_message, var.message) + type = "query alert" + + query = < ${var.disk_inodes_threshold_critical} +EOQ + + monitor_thresholds { + warning = var.disk_inodes_threshold_warning + critical = var.disk_inodes_threshold_critical + } + + evaluation_delay = var.evaluation_delay + new_host_delay = var.new_host_delay + notify_no_data = false + notify_audit = false + timeout_h = 0 + include_tags = true + locked = false + require_full_window = true + + tags = concat(["env:${var.environment}", "type:system", "provider:disk", "resource:generic", "team:claranet", "created-by:terraform"], var.disk_inodes_extra_tags) +} + +resource "datadog_monitor" "memory" { + count = var.memory_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Usable Memory {{#is_alert}}{{{comparator}}} {{threshold}}% ({{value}}%){{/is_alert}}{{#is_warning}}{{{comparator}}} {{warn_threshold}}% ({{value}}%){{/is_warning}}" + message = var.memory_message + type = "query alert" + + query = < [terraform](#requirement\_terraform) | >= 0.12.31 | +| [datadog](#requirement\_datadog) | >= 3.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [datadog](#provider\_datadog) | 3.1.2 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [filter-tags](#module\_filter-tags) | ../../common/filter-tags | n/a | + +## Resources + +| Name | Type | +|------|------| +| [datadog_monitor.host_unreachable](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [environment](#input\_environment) | Architecture Environment | `string` | n/a | yes | +| [evaluation\_delay](#input\_evaluation\_delay) | Delay in seconds for the metric evaluation | `number` | `15` | no | +| [filter\_tags\_custom](#input\_filter\_tags\_custom) | Tags used for custom filtering when filter\_tags\_use\_defaults is false | `string` | `"*"` | no | +| [filter\_tags\_custom\_excluded](#input\_filter\_tags\_custom\_excluded) | Tags excluded for custom filtering when filter\_tags\_use\_defaults is false | `string` | `""` | no | +| [filter\_tags\_use\_defaults](#input\_filter\_tags\_use\_defaults) | Use default filter tags convention | `string` | `"true"` | no | +| [message](#input\_message) | Message sent when an alert is triggered | `any` | n/a | yes | +| [new\_host\_delay](#input\_new\_host\_delay) | Delay in seconds before monitor new resource | `number` | `300` | no | +| [notify\_no\_data](#input\_notify\_no\_data) | Will raise no data alert if set to true | `bool` | `true` | no | +| [prefix\_slug](#input\_prefix\_slug) | Prefix string to prepend between brackets on every monitors names | `string` | `""` | no | +| [unreachable\_enabled](#input\_unreachable\_enabled) | Flag to enable Host unreachable monitor | `string` | `"true"` | no | +| [unreachable\_extra\_tags](#input\_unreachable\_extra\_tags) | Extra tags for Host unreachable monitor | `list(string)` | `[]` | no | +| [unreachable\_message](#input\_unreachable\_message) | Custom message for Host unreachable monitor | `string` | `""` | no | +| [unreachable\_no\_data\_timeframe](#input\_unreachable\_no\_data\_timeframe) | Timeframe for Host unreachable monitor to alert on no data | `string` | `20` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [host\_unreachable\_id](#output\_host\_unreachable\_id) | id for monitor host\_unreachable | +## Related documentation + diff --git a/.terraform/modules/datadog-monitors-system-generic/system/unreachable/inputs.tf b/.terraform/modules/datadog-monitors-system-generic/system/unreachable/inputs.tf new file mode 100755 index 0000000..d0388dc --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/system/unreachable/inputs.tf @@ -0,0 +1,72 @@ +# Global Terraform +variable "environment" { + description = "Architecture Environment" + type = string +} + +# Global DataDog +variable "evaluation_delay" { + description = "Delay in seconds for the metric evaluation" + default = 15 +} + +variable "new_host_delay" { + description = "Delay in seconds before monitor new resource" + default = 300 +} + +variable "prefix_slug" { + description = "Prefix string to prepend between brackets on every monitors names" + default = "" +} + +variable "notify_no_data" { + description = "Will raise no data alert if set to true" + default = true +} + +variable "message" { + description = "Message sent when an alert is triggered" +} + +variable "filter_tags_use_defaults" { + description = "Use default filter tags convention" + default = "true" +} + +variable "filter_tags_custom" { + description = "Tags used for custom filtering when filter_tags_use_defaults is false" + default = "*" +} + +variable "filter_tags_custom_excluded" { + description = "Tags excluded for custom filtering when filter_tags_use_defaults is false" + default = "" +} + +# Unreachable + +variable "unreachable_enabled" { + description = "Flag to enable Host unreachable monitor" + type = string + default = "true" +} + +variable "unreachable_extra_tags" { + description = "Extra tags for Host unreachable monitor" + type = list(string) + default = [] +} + +variable "unreachable_message" { + description = "Custom message for Host unreachable monitor" + type = string + default = "" +} + +variable "unreachable_no_data_timeframe" { + description = "Timeframe for Host unreachable monitor to alert on no data" + type = string + default = 20 +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/system/unreachable/modules.tf b/.terraform/modules/datadog-monitors-system-generic/system/unreachable/modules.tf new file mode 100755 index 0000000..4c44673 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/system/unreachable/modules.tf @@ -0,0 +1,10 @@ +module "filter-tags" { + source = "../../common/filter-tags" + + environment = var.environment + resource = "system" + filter_tags_use_defaults = var.filter_tags_use_defaults + filter_tags_custom = var.filter_tags_custom + filter_tags_custom_excluded = var.filter_tags_custom_excluded +} + diff --git a/.terraform/modules/datadog-monitors-system-generic/system/unreachable/monitors-unreachable.tf b/.terraform/modules/datadog-monitors-system-generic/system/unreachable/monitors-unreachable.tf new file mode 100755 index 0000000..1af06c9 --- /dev/null +++ b/.terraform/modules/datadog-monitors-system-generic/system/unreachable/monitors-unreachable.tf @@ -0,0 +1,28 @@ +resource "datadog_monitor" "host_unreachable" { + count = var.unreachable_enabled == "true" ? 1 : 0 + name = "${var.prefix_slug == "" ? "" : "[${var.prefix_slug}]"}[${var.environment}] Host unreachable" + message = coalesce(var.unreachable_message, var.message) + type = "service check" + + query = < +# terraform-null-label [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-null-label.svg)](https://github.com/cloudposse/terraform-null-label/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) + + +[![README Header][readme_header_img]][readme_header_link] + +[![Cloud Posse][logo]](https://cpco.io/homepage) + + + +Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + +This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. +However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). +So if you prefer the term `stage` to `environment` +you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. +- If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. +- If you want the attributes in a different order, you can specify that, too, with the `label_order` list. +- You can set a maximum length for the name, and the module will create a unique name that fits within that length. +- You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. +- The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + +It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. +For example, if you have 10 instances, there should be 10 different labels. +However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + +All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + +**NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. +With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + +- Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. +- Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. +- Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. + + +--- + +This project is part of our comprehensive ["SweetOps"](https://cpco.io/sweetops) approach towards DevOps. +[][share_email] +[][share_googleplus] +[][share_facebook] +[][share_reddit] +[][share_linkedin] +[][share_twitter] + + +[![Terraform Open Source Modules](https://docs.cloudposse.com/images/terraform-open-source-modules.svg)][terraform_modules] + + + +It's 100% Open Source and licensed under the [APACHE2](LICENSE). + + + + + + + +We literally have [*hundreds of terraform modules*][terraform_modules] that are Open Source and well-maintained. Check them out! + + + + + + + +## Security & Compliance [](https://bridgecrew.io/) + +Security scanning is graciously provided by Bridgecrew. Bridgecrew is the leading fully hosted, cloud-native solution providing continuous Terraform security and compliance. + +| Benchmark | Description | +|--------|---------------| +| [![Infrastructure Security](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/general)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=INFRASTRUCTURE+SECURITY) | Infrastructure Security Compliance | +| [![CIS KUBERNETES](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_kubernetes)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+KUBERNETES+V1.5) | Center for Internet Security, KUBERNETES Compliance | +| [![CIS AWS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_aws)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AWS+V1.2) | Center for Internet Security, AWS Compliance | +| [![CIS AZURE](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_azure)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AZURE+V1.1) | Center for Internet Security, AZURE Compliance | +| [![PCI-DSS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/pci)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=PCI-DSS+V3.2) | Payment Card Industry Data Security Standards Compliance | +| [![NIST-800-53](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/nist)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=NIST-800-53) | National Institute of Standards and Technology Compliance | +| [![ISO27001](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/iso)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=ISO27001) | Information Security Management System, ISO/IEC 27001 Compliance | +| [![SOC2](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/soc2)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=SOC2)| Service Organization Control 2 Compliance | +| [![CIS GCP](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_gcp)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+GCP+V1.1) | Center for Internet Security, GCP Compliance | +| [![HIPAA](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/hipaa)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=HIPAA) | Health Insurance Portability and Accountability Compliance | + + + +## Usage + + +**IMPORTANT:** We do not pin modules to versions in our examples because of the +difficulty of keeping the versions in the documentation in sync with the latest released versions. +We highly recommend that in your code you pin the version to the exact version you are +using so that your infrastructure remains stable, and update versions in a +systematic way so that they do not catch you by surprise. + +Also, because of a bug in the Terraform registry ([hashicorp/terraform#21417](https://github.com/hashicorp/terraform/issues/21417)), +the registry shows many of our inputs as required when in fact they are optional. +The table below correctly indicates which inputs are required. + + +### Defaults + +Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. +The context object is a single object that contains all the input values for `terraform-null-label`. +However, each input value can also be specified individually by name as a standard Terraform variable, +and the value of those variables, when set to something other than `null`, will override the value +in the context object. In order to allow chaining of these objects, where the context object input to one +module is transformed and passed to the next module, all the variables default to `null` or empty collections. +The actual default values used when nothing is explicitly set are describe in the documentation below. + +For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, +`terraform-null-label` will actually use the default delimiter `-` (hyphen). + +A non-obvious but intentional consequence of this design is that once a module sets a non-default value, +future modules in the chain cannot reset the value back to the original default. Insted, the new setting +becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, +so once a tag is added, it will remain in the tag set and cannot be removed, although its value can +be overwritten. + +### Simple Example + +```hcl +module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} +``` + +This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` +(you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + +Now reference the label when creating an instance: + +```hcl +resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags +} +``` + +Or define a security group: + +```hcl +resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} +``` + + +### Advanced Example + +Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + +```hcl +module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] +} + +module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] +} +``` + +
+ +### Advanced Example 2 + +Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + +```hcl +tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } +] +``` + +Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + +```hcl +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} +``` + +
+ +### Advanced Example 3 + +See [complete example](./examples/complete) for even more examples. + +This example shows how you can pass the `context` output of one label module to the next label_module, +allowing you to create one label that has the base set of values, and then creating every extra label +as a derivative of that. + +
Click to show + +```hcl +module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} +``` + +This creates label outputs like this: + +```hcl +label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" +} +label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } +} +label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } +} +label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" +} +label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" +} +label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } +} +label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" +} +label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, +] +label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" +} +label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } +} +label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } +} +label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" +} + +``` + +
+ + + + + + + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + + + + +## Share the Love + +Like this project? Please give it a ★ on [our GitHub](https://github.com/cloudposse/terraform-null-label)! (it helps us **a lot**) + +Are you using this project or any of our other projects? Consider [leaving a testimonial][testimonial]. =) + + +## Related Projects + +Check out these related projects. + +- [terraform-terraform-label](https://github.com/cloudposse/terraform-terraform-label) - Terraform Module to define a consistent naming convention by (namespace, environment, stage, name, [attributes]) + + + +## Help + +**Got a question?** We got answers. + +File a GitHub [issue](https://github.com/cloudposse/terraform-null-label/issues), send us an [email][email] or join our [Slack Community][slack]. + +[![README Commercial Support][readme_commercial_support_img]][readme_commercial_support_link] + +## DevOps Accelerator for Startups + + +We are a [**DevOps Accelerator**][commercial_support]. We'll help you build your cloud infrastructure from the ground up so you can own it. Then we'll show you how to operate it and stick around for as long as you need us. + +[![Learn More](https://img.shields.io/badge/learn%20more-success.svg?style=for-the-badge)][commercial_support] + +Work directly with our team of DevOps experts via email, slack, and video conferencing. + +We deliver 10x the value for a fraction of the cost of a full-time engineer. Our track record is not even funny. If you want things done right and you need it done FAST, then we're your best bet. + +- **Reference Architecture.** You'll get everything you need from the ground up built using 100% infrastructure as code. +- **Release Engineering.** You'll have end-to-end CI/CD with unlimited staging environments. +- **Site Reliability Engineering.** You'll have total visibility into your apps and microservices. +- **Security Baseline.** You'll have built-in governance with accountability and audit logs for all changes. +- **GitOps.** You'll be able to operate your infrastructure via Pull Requests. +- **Training.** You'll receive hands-on training so your team can operate what we build. +- **Questions.** You'll have a direct line of communication between our teams via a Shared Slack channel. +- **Troubleshooting.** You'll get help to triage when things aren't working. +- **Code Reviews.** You'll receive constructive feedback on Pull Requests. +- **Bug Fixes.** We'll rapidly work with you to fix any bugs in our projects. + +## Slack Community + +Join our [Open Source Community][slack] on Slack. It's **FREE** for everyone! Our "SweetOps" community is where you get to talk with others who share a similar vision for how to rollout and manage infrastructure. This is the best place to talk shop, ask questions, solicit feedback, and work together as a community to build totally *sweet* infrastructure. + +## Discourse Forums + +Participate in our [Discourse Forums][discourse]. Here you'll find answers to commonly asked questions. Most questions will be related to the enormous number of projects we support on our GitHub. Come here to collaborate on answers, find solutions, and get ideas about the products and services we value. It only takes a minute to get started! Just sign in with SSO using your GitHub account. + +## Newsletter + +Sign up for [our newsletter][newsletter] that covers everything on our technology radar. Receive updates on what we're up to on GitHub as well as awesome new projects we discover. + +## Office Hours + +[Join us every Wednesday via Zoom][office_hours] for our weekly "Lunch & Learn" sessions. It's **FREE** for everyone! + +[![zoom](https://img.cloudposse.com/fit-in/200x200/https://cloudposse.com/wp-content/uploads/2019/08/Powered-by-Zoom.png")][office_hours] + +## Contributing + +### Bug Reports & Feature Requests + +Please use the [issue tracker](https://github.com/cloudposse/terraform-null-label/issues) to report any bugs or file feature requests. + +### Developing + +If you are interested in being a contributor and want to get involved in developing this project or [help out](https://cpco.io/help-out) with our other projects, we would love to hear from you! Shoot us an [email][email]. + +In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. + + 1. **Fork** the repo on GitHub + 2. **Clone** the project to your own machine + 3. **Commit** changes to your own branch + 4. **Push** your work back up to your fork + 5. Submit a **Pull Request** so that we can review your changes + +**NOTE:** Be sure to merge the latest changes from "upstream" before making a pull request! + + +## Copyright + +Copyright © 2017-2021 [Cloud Posse, LLC](https://cpco.io/copyright) + + + +## License + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +See [LICENSE](LICENSE) for full details. + +```text +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +``` + + + + + + + + + +## Trademarks + +All other trademarks referenced herein are the property of their respective owners. + +## About + +This project is maintained and funded by [Cloud Posse, LLC][website]. Like it? Please let us know by [leaving a testimonial][testimonial]! + +[![Cloud Posse][logo]][website] + +We're a [DevOps Professional Services][hire] company based in Los Angeles, CA. We ❤️ [Open Source Software][we_love_open_source]. + +We offer [paid support][commercial_support] on all of our projects. + +Check out [our other projects][github], [follow us on twitter][twitter], [apply for a job][jobs], or [hire us][hire] to help with your cloud strategy and implementation. + + + +### Contributors + + +| [![Erik Osterman][osterman_avatar]][osterman_homepage]
[Erik Osterman][osterman_homepage] | [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]
[Andriy Knysh][aknysh_homepage] | [![Igor Rodionov][goruha_avatar]][goruha_homepage]
[Igor Rodionov][goruha_homepage] | [![Sergey Vasilyev][s2504s_avatar]][s2504s_homepage]
[Sergey Vasilyev][s2504s_homepage] | [![Michael Pereira][MichaelPereira_avatar]][MichaelPereira_homepage]
[Michael Pereira][MichaelPereira_homepage] | [![Jamie Nelson][Jamie-BitFlight_avatar]][Jamie-BitFlight_homepage]
[Jamie Nelson][Jamie-BitFlight_homepage] | [![Vladimir][SweetOps_avatar]][SweetOps_homepage]
[Vladimir][SweetOps_homepage] | [![Daren Desjardins][darend_avatar]][darend_homepage]
[Daren Desjardins][darend_homepage] | [![Maarten van der Hoef][maartenvanderhoef_avatar]][maartenvanderhoef_homepage]
[Maarten van der Hoef][maartenvanderhoef_homepage] | [![Adam Tibbing][tibbing_avatar]][tibbing_homepage]
[Adam Tibbing][tibbing_homepage] | +|---|---|---|---|---|---|---|---|---|---| + + + [osterman_homepage]: https://github.com/osterman + [osterman_avatar]: https://img.cloudposse.com/150x150/https://github.com/osterman.png + [aknysh_homepage]: https://github.com/aknysh + [aknysh_avatar]: https://img.cloudposse.com/150x150/https://github.com/aknysh.png + [goruha_homepage]: https://github.com/goruha + [goruha_avatar]: https://img.cloudposse.com/150x150/https://github.com/goruha.png + [s2504s_homepage]: https://github.com/s2504s + [s2504s_avatar]: https://img.cloudposse.com/150x150/https://github.com/s2504s.png + [MichaelPereira_homepage]: https://github.com/MichaelPereira + [MichaelPereira_avatar]: https://img.cloudposse.com/150x150/https://github.com/MichaelPereira.png + [Jamie-BitFlight_homepage]: https://github.com/Jamie-BitFlight + [Jamie-BitFlight_avatar]: https://img.cloudposse.com/150x150/https://github.com/Jamie-BitFlight.png + [SweetOps_homepage]: https://github.com/SweetOps + [SweetOps_avatar]: https://img.cloudposse.com/150x150/https://github.com/SweetOps.png + [darend_homepage]: https://github.com/darend + [darend_avatar]: https://img.cloudposse.com/150x150/https://github.com/darend.png + [maartenvanderhoef_homepage]: https://github.com/maartenvanderhoef + [maartenvanderhoef_avatar]: https://img.cloudposse.com/150x150/https://github.com/maartenvanderhoef.png + [tibbing_homepage]: https://github.com/tibbing + [tibbing_avatar]: https://img.cloudposse.com/150x150/https://github.com/tibbing.png + +[![README Footer][readme_footer_img]][readme_footer_link] +[![Beacon][beacon]][website] + + [logo]: https://cloudposse.com/logo-300x69.svg + [docs]: https://cpco.io/docs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=docs + [website]: https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=website + [github]: https://cpco.io/github?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=github + [jobs]: https://cpco.io/jobs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=jobs + [hire]: https://cpco.io/hire?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=hire + [slack]: https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=slack + [linkedin]: https://cpco.io/linkedin?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=linkedin + [twitter]: https://cpco.io/twitter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=twitter + [testimonial]: https://cpco.io/leave-testimonial?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=testimonial + [office_hours]: https://cloudposse.com/office-hours?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=office_hours + [newsletter]: https://cpco.io/newsletter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=newsletter + [discourse]: https://ask.sweetops.com/?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=discourse + [email]: https://cpco.io/email?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=email + [commercial_support]: https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=commercial_support + [we_love_open_source]: https://cpco.io/we-love-open-source?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=we_love_open_source + [terraform_modules]: https://cpco.io/terraform-modules?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=terraform_modules + [readme_header_img]: https://cloudposse.com/readme/header/img + [readme_header_link]: https://cloudposse.com/readme/header/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_header_link + [readme_footer_img]: https://cloudposse.com/readme/footer/img + [readme_footer_link]: https://cloudposse.com/readme/footer/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_footer_link + [readme_commercial_support_img]: https://cloudposse.com/readme/commercial-support/img + [readme_commercial_support_link]: https://cloudposse.com/readme/commercial-support/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_commercial_support_link + [share_twitter]: https://twitter.com/intent/tweet/?text=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_linkedin]: https://www.linkedin.com/shareArticle?mini=true&title=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_reddit]: https://reddit.com/submit/?url=https://github.com/cloudposse/terraform-null-label + [share_facebook]: https://facebook.com/sharer/sharer.php?u=https://github.com/cloudposse/terraform-null-label + [share_googleplus]: https://plus.google.com/share?url=https://github.com/cloudposse/terraform-null-label + [share_email]: mailto:?subject=terraform-null-label&body=https://github.com/cloudposse/terraform-null-label + [beacon]: https://ga-beacon.cloudposse.com/UA-76589703-4/cloudposse/terraform-null-label?pixel&cs=github&cm=readme&an=terraform-null-label diff --git a/.terraform/modules/datadog_integration.core_label/README.yaml b/.terraform/modules/datadog_integration.core_label/README.yaml new file mode 100755 index 0000000..42bdb84 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/README.yaml @@ -0,0 +1,618 @@ +name: terraform-null-label +tags: +- aws +- terraform +- terraform-modules +- naming-convention +- name +- namespace +- stage +categories: +- terraform-modules/supported +license: APACHE2 +github_repo: cloudposse/terraform-null-label +badges: +- name: Latest Release + image: https://img.shields.io/github/release/cloudposse/terraform-null-label.svg + url: https://github.com/cloudposse/terraform-null-label/releases/latest +- name: Slack Community + image: https://slack.cloudposse.com/badge.svg + url: https://slack.cloudposse.com +related: +- name: terraform-terraform-label + description: Terraform Module to define a consistent naming convention by (namespace, + environment, stage, name, [attributes]) + url: https://github.com/cloudposse/terraform-terraform-label +description: |- + Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + + This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. + However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). + So if you prefer the term `stage` to `environment` + you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. + - If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. + - If you want the attributes in a different order, you can specify that, too, with the `label_order` list. + - You can set a maximum length for the name, and the module will create a unique name that fits within that length. + - You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. + - The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + + It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. + For example, if you have 10 instances, there should be 10 different labels. + However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + + All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + + **NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. + With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + + - Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. + - Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. + - Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. +usage: |- + ### Defaults + + Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. + The context object is a single object that contains all the input values for `terraform-null-label`. + However, each input value can also be specified individually by name as a standard Terraform variable, + and the value of those variables, when set to something other than `null`, will override the value + in the context object. In order to allow chaining of these objects, where the context object input to one + module is transformed and passed to the next module, all the variables default to `null` or empty collections. + The actual default values used when nothing is explicitly set are describe in the documentation below. + + For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, + `terraform-null-label` will actually use the default delimiter `-` (hyphen). + + A non-obvious but intentional consequence of this design is that once a module sets a non-default value, + future modules in the chain cannot reset the value back to the original default. Insted, the new setting + becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, + so once a tag is added, it will remain in the tag set and cannot be removed, although its value can + be overwritten. + + ### Simple Example + + ```hcl + module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + ``` + + This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` + (you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + + Now reference the label when creating an instance: + + ```hcl + resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags + } + ``` + + Or define a security group: + + ```hcl + resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + } + ``` + + + ### Advanced Example + + Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + + ```hcl + module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] + } + + module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] + } + ``` + +
+ + ### Advanced Example 2 + + Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + + ```hcl + tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } + ] + ``` + + Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + + ```hcl + ################################ + # terraform-null-label example # + ################################ + module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } + } + + ####################### + # Launch template # + ####################### + resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } + } + + ###################### + # Autoscaling group # + ###################### + resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps + } + ``` + +
+ + ### Advanced Example 3 + + See [complete example](./examples/complete) for even more examples. + + This example shows how you can pass the `context` output of one label module to the next label_module, + allowing you to create one label that has the base set of values, and then creating every extra label + as a derivative of that. + +
Click to show + + ```hcl + module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } + } + + module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } + } + + module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } + } + ``` + + This creates label outputs like this: + + ```hcl + label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" + } + label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } + } + label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + } + label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" + } + label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } + } + label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" + } + label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, + ] + label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" + } + label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } + } + label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + } + label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + + ``` + +
+ +include: +- docs/targets.md +- docs/terraform.md +contributors: +- name: Erik Osterman + github: osterman +- name: Andriy Knysh + github: aknysh +- name: Igor Rodionov + github: goruha +- name: Sergey Vasilyev + github: s2504s +- name: Michael Pereira + github: MichaelPereira +- name: Jamie Nelson + github: Jamie-BitFlight +- name: Vladimir + github: SweetOps +- name: Daren Desjardins + github: darend +- name: Maarten van der Hoef + github: maartenvanderhoef +- name: Adam Tibbing + github: tibbing diff --git a/.terraform/modules/datadog_integration.core_label/docs/targets.md b/.terraform/modules/datadog_integration.core_label/docs/targets.md new file mode 100755 index 0000000..3dce8b3 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/docs/targets.md @@ -0,0 +1,12 @@ + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + diff --git a/.terraform/modules/datadog_integration.core_label/docs/terraform.md b/.terraform/modules/datadog_integration.core_label/docs/terraform.md new file mode 100755 index 0000000..d4f48f4 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/docs/terraform.md @@ -0,0 +1,54 @@ + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + diff --git a/.terraform/modules/datadog_integration.core_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars b/.terraform/modules/datadog_integration.core_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars new file mode 100755 index 0000000..f7c725f --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars @@ -0,0 +1,12 @@ +namespace = "eg" +stage = "prod" +name = "app" + +tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" +} + +additional_tag_map = { + propagate_at_launch = "true" +} diff --git a/.terraform/modules/datadog_integration.core_label/examples/autoscalinggroup/context.tf b/.terraform/modules/datadog_integration.core_label/examples/autoscalinggroup/context.tf new file mode 100755 index 0000000..b97f05f --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/autoscalinggroup/context.tf @@ -0,0 +1,216 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration.core_label/examples/autoscalinggroup/main.tf b/.terraform/modules/datadog_integration.core_label/examples/autoscalinggroup/main.tf new file mode 100755 index 0000000..f0d3aa6 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/autoscalinggroup/main.tf @@ -0,0 +1,104 @@ +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + + context = module.this.context +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template { + id = aws_launch_template.default.id + version = "$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} + +################################ +# Provider # +################################ +provider "aws" { + region = "eu-west-1" + + # Make it faster by skipping unneeded checks here + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +############################################################## +# Data sources to get VPC, subnets and security group details +############################################################## +data "aws_vpc" "default" { + default = true +} + +data "aws_subnet_ids" "all" { + vpc_id = data.aws_vpc.default.id +} + +data "aws_security_group" "default" { + vpc_id = data.aws_vpc.default.id + name = "default" +} + +data "aws_ami" "amazon_linux" { + most_recent = true + + owners = ["amazon"] + + filter { + name = "name" + + values = [ + "amzn-ami-hvm-*-x86_64-gp2", + ] + } + + filter { + name = "owner-alias" + + values = [ + "amazon", + ] + } +} + diff --git a/.terraform/modules/datadog_integration.core_label/examples/autoscalinggroup/outputs.tf b/.terraform/modules/datadog_integration.core_label/examples/autoscalinggroup/outputs.tf new file mode 100755 index 0000000..f8fcce5 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/autoscalinggroup/outputs.tf @@ -0,0 +1,12 @@ +# terraform-null-label example used here: Output list of tags applied in each format +output "tags_as_list_of_maps" { + value = module.label.tags_as_list_of_maps +} + +output "tags" { + value = module.label.tags +} + +output "id" { + value = module.label.id +} diff --git a/.terraform/modules/datadog_integration.core_label/examples/autoscalinggroup/versions.tf b/.terraform/modules/datadog_integration.core_label/examples/autoscalinggroup/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/autoscalinggroup/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration.core_label/examples/complete/complete.auto.tfvars b/.terraform/modules/datadog_integration.core_label/examples/complete/complete.auto.tfvars new file mode 100755 index 0000000..e7bc519 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/complete/complete.auto.tfvars @@ -0,0 +1,10 @@ +namespace = "cp" +environment = "uw2" +stage = "prd" +name = "null-label" + +delimiter = "" +id_length_limit = 6 + +label_key_case = "lower" +label_value_case = "upper" diff --git a/.terraform/modules/datadog_integration.core_label/examples/complete/context.tf b/.terraform/modules/datadog_integration.core_label/examples/complete/context.tf new file mode 100755 index 0000000..973d4dc --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/complete/context.tf @@ -0,0 +1,217 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration.core_label/examples/complete/label1.tf b/.terraform/modules/datadog_integration.core_label/examples/complete/label1.tf new file mode 100755 index 0000000..8da353b --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/complete/label1.tf @@ -0,0 +1,42 @@ +module "label1" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label1" { + value = { + id = module.label1.id + name = module.label1.name + namespace = module.label1.namespace + stage = module.label1.stage + attributes = module.label1.attributes + delimiter = module.label1.delimiter + } +} + +output "label1_tags" { + value = module.label1.tags +} + +output "label1_context" { + value = module.label1.context +} + +output "label1_normalized_context" { + value = module.label1.normalized_context +} + + + diff --git a/.terraform/modules/datadog_integration.core_label/examples/complete/label1t1.tf b/.terraform/modules/datadog_integration.core_label/examples/complete/label1t1.tf new file mode 100755 index 0000000..2bcb362 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/complete/label1t1.tf @@ -0,0 +1,18 @@ +module "label1t1" { + source = "../../" + + id_length_limit = 28 + + context = module.label1.context +} + +output "label1t1" { + value = { + id = module.label1t1.id + id_full = module.label1t1.id_full + } +} + +output "label1t1_tags" { + value = module.label1t1.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration.core_label/examples/complete/label1t2.tf b/.terraform/modules/datadog_integration.core_label/examples/complete/label1t2.tf new file mode 100755 index 0000000..5df651e --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/complete/label1t2.tf @@ -0,0 +1,18 @@ +module "label1t2" { + source = "../../" + + id_length_limit = 29 + + context = module.label1.context +} + +output "label1t2" { + value = { + id = module.label1t2.id + id_full = module.label1t2.id_full + } +} + +output "label1t2_tags" { + value = module.label1t2.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration.core_label/examples/complete/label2.tf b/.terraform/modules/datadog_integration.core_label/examples/complete/label2.tf new file mode 100755 index 0000000..faf7450 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/complete/label2.tf @@ -0,0 +1,42 @@ +module "label2" { + source = "../../" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + regex_replace_chars = "/[^a-zA-Z0-9-+]/" + + additional_tag_map = { + propagate_at_launch = "true" + additional_tag = "yes" + } + + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +output "label2" { + value = { + id = module.label2.id + name = module.label2.name + namespace = module.label2.namespace + stage = module.label2.stage + attributes = module.label2.attributes + delimiter = module.label2.delimiter + } +} + +output "label2_tags" { + value = module.label2.tags +} + +output "label2_tags_as_list_of_maps" { + value = module.label2.tags_as_list_of_maps +} + +output "label2_context" { + value = module.label2.context +} diff --git a/.terraform/modules/datadog_integration.core_label/examples/complete/label3c.tf b/.terraform/modules/datadog_integration.core_label/examples/complete/label3c.tf new file mode 100755 index 0000000..338a636 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/complete/label3c.tf @@ -0,0 +1,36 @@ +module "label3c" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3c" { + value = { + id = module.label3c.id + name = module.label3c.name + namespace = module.label3c.namespace + stage = module.label3c.stage + attributes = module.label3c.attributes + delimiter = module.label3c.delimiter + } +} + +output "label3c_tags" { + value = module.label3c.tags +} + +output "label3c_context" { + value = module.label3c.context +} + +output "label3c_normalized_context" { + value = module.label3c.normalized_context +} diff --git a/.terraform/modules/datadog_integration.core_label/examples/complete/label3n.tf b/.terraform/modules/datadog_integration.core_label/examples/complete/label3n.tf new file mode 100755 index 0000000..ca51282 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/complete/label3n.tf @@ -0,0 +1,36 @@ +module "label3n" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.normalized_context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3n" { + value = { + id = module.label3n.id + name = module.label3n.name + namespace = module.label3n.namespace + stage = module.label3n.stage + attributes = module.label3n.attributes + delimiter = module.label3n.delimiter + } +} + +output "label3n_tags" { + value = module.label3n.tags +} + +output "label3n_context" { + value = module.label3n.context +} + +output "label3n_normalized_context" { + value = module.label3n.normalized_context +} diff --git a/.terraform/modules/datadog_integration.core_label/examples/complete/label4.tf b/.terraform/modules/datadog_integration.core_label/examples/complete/label4.tf new file mode 100755 index 0000000..74e3ca1 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/complete/label4.tf @@ -0,0 +1,34 @@ +module "label4" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + name = "Example Cluster" + attributes = ["big", "fat", "honking", "cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label4" { + value = { + id = module.label4.id + name = module.label4.name + namespace = module.label4.namespace + stage = module.label4.stage + attributes = module.label4.attributes + delimiter = module.label4.delimiter + } +} + +output "label4_tags" { + value = module.label4.tags +} + +output "label4_context" { + value = module.label4.context +} diff --git a/.terraform/modules/datadog_integration.core_label/examples/complete/label5.tf b/.terraform/modules/datadog_integration.core_label/examples/complete/label5.tf new file mode 100755 index 0000000..0f0a76e --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/complete/label5.tf @@ -0,0 +1,33 @@ +module "label5" { + source = "../../" + enabled = false + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + } +} + +output "label5" { + value = { + id = module.label5.id + name = module.label5.name + namespace = module.label5.namespace + stage = module.label5.stage + attributes = module.label5.attributes + delimiter = module.label5.delimiter + } +} + +output "label5_tags" { + value = module.label5.tags +} + +output "label5_context" { + value = module.label5.context +} diff --git a/.terraform/modules/datadog_integration.core_label/examples/complete/label6f.tf b/.terraform/modules/datadog_integration.core_label/examples/complete/label6f.tf new file mode 100755 index 0000000..1ce1bab --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/complete/label6f.tf @@ -0,0 +1,20 @@ +module "label6f" { + source = "../../" + + delimiter = "~" + id_length_limit = 0 + + # Use values from tfvars + context = module.this.context +} + +output "label6f" { + value = { + id = module.label6f.id + id_full = module.label6f.id_full + } +} + +output "label6f_tags" { + value = module.label6f.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration.core_label/examples/complete/label6t.tf b/.terraform/modules/datadog_integration.core_label/examples/complete/label6t.tf new file mode 100755 index 0000000..b5d9bc1 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/complete/label6t.tf @@ -0,0 +1,19 @@ +module "label6t" { + source = "../../" + + # Use values from tfvars, + # specifically: complete.auto.tfvars + context = module.this.context +} + +output "label6t" { + value = { + id = module.label6t.id + id_full = module.label6t.id_full + id_length_limit = module.this.context.id_length_limit + } +} + +output "label6t_tags" { + value = module.label6t.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration.core_label/examples/complete/label7.tf b/.terraform/modules/datadog_integration.core_label/examples/complete/label7.tf new file mode 100755 index 0000000..bb365d4 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/complete/label7.tf @@ -0,0 +1,44 @@ +module "label7a" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + } +} + +module "label7" { + source = "../../" + + attributes = ["nodegroup"] + + context = module.label7a.context +} + + +output "label7" { + value = { + id = module.label7.id + name = module.label7.name + namespace = module.label7.namespace + stage = module.label7.stage + attributes = module.label7.attributes + delimiter = module.label7.delimiter + } +} + +output "label7_id" { + value = module.label7.id +} + +output "label7_attributes" { + value = module.label7.attributes +} + +output "label7_context" { + value = module.label7.context +} diff --git a/.terraform/modules/datadog_integration.core_label/examples/complete/label8d.tf b/.terraform/modules/datadog_integration.core_label/examples/complete/label8d.tf new file mode 100755 index 0000000..4252419 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/complete/label8d.tf @@ -0,0 +1,44 @@ +module "label8d" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8d_context" { + source = "../../" + + context = module.label8d.context +} + +output "label8d_context_id" { + value = module.label8d_context.id +} + +output "label8d_context_context" { + value = module.label8d_context.context +} + +output "label8d_context_tags" { + value = module.label8d_context.tags +} + +output "label8d_id" { + value = module.label8d.id +} + +output "label8d_context" { + value = module.label8d.context +} + +output "label8d_tags" { + value = module.label8d.tags +} diff --git a/.terraform/modules/datadog_integration.core_label/examples/complete/label8dcd.tf b/.terraform/modules/datadog_integration.core_label/examples/complete/label8dcd.tf new file mode 100755 index 0000000..ccdae21 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/complete/label8dcd.tf @@ -0,0 +1,24 @@ +module "label8dcd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "x" +} + +module "label8dcd_context" { + source = "../../" + + context = module.label8dcd.context +} + +output "label8dcd_context_id" { + value = module.label8dcd_context.id +} + +output "label8dcd_id" { + value = module.label8dcd.id +} diff --git a/.terraform/modules/datadog_integration.core_label/examples/complete/label8dnd.tf b/.terraform/modules/datadog_integration.core_label/examples/complete/label8dnd.tf new file mode 100755 index 0000000..2edb378 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/complete/label8dnd.tf @@ -0,0 +1,24 @@ +module "label8dnd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "" +} + +module "label8dnd_context" { + source = "../../" + + context = module.label8dnd.context +} + +output "label8dnd_context_id" { + value = module.label8dnd_context.id +} + +output "label8dnd_id" { + value = module.label8dnd.id +} diff --git a/.terraform/modules/datadog_integration.core_label/examples/complete/label8l.tf b/.terraform/modules/datadog_integration.core_label/examples/complete/label8l.tf new file mode 100755 index 0000000..7462f9e --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/complete/label8l.tf @@ -0,0 +1,46 @@ +module "label8l" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "lower" + label_value_case = "lower" + + tags = { + "kubernetes.io/cluster/" = "shared" + "upperTEST" = "testUPPER" + } +} + +module "label8l_context" { + source = "../../" + + context = module.label8l.context +} + +output "label8l_context_id" { + value = module.label8l_context.id +} + +output "label8l_context_context" { + value = module.label8l_context.context +} + +output "label8l_context_tags" { + value = module.label8l_context.tags +} + +output "label8l_id" { + value = module.label8l.id +} + +output "label8l_context" { + value = module.label8l.context +} + +output "label8l_tags" { + value = module.label8l.tags +} diff --git a/.terraform/modules/datadog_integration.core_label/examples/complete/label8n.tf b/.terraform/modules/datadog_integration.core_label/examples/complete/label8n.tf new file mode 100755 index 0000000..fd4ad57 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/complete/label8n.tf @@ -0,0 +1,45 @@ +module "label8n" { + source = "../../" + + enabled = true + namespace = "EG" + environment = "demo" + name = "blue" + attributes = ["eks", "ClusteR"] + delimiter = "-" + label_value_case = "none" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8n_context" { + source = "../../" + + context = module.label8n.context +} + +output "label8n_context_id" { + value = module.label8n_context.id +} + +output "label8n_context_context" { + value = module.label8n_context.context +} + +output "label8n_context_tags" { + value = module.label8n_context.tags +} + +output "label8n_id" { + value = module.label8n.id +} + +output "label8n_context" { + value = module.label8n.context +} + +output "label8n_tags" { + value = module.label8n.tags +} diff --git a/.terraform/modules/datadog_integration.core_label/examples/complete/label8t.tf b/.terraform/modules/datadog_integration.core_label/examples/complete/label8t.tf new file mode 100755 index 0000000..cb54c7a --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/complete/label8t.tf @@ -0,0 +1,45 @@ +module "label8t" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["EKS", "cluster"] + delimiter = "-" + label_key_case = "title" + label_value_case = "title" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8t_context" { + source = "../../" + + context = module.label8t.context +} + +output "label8t_context_id" { + value = module.label8t_context.id +} + +output "label8t_context_context" { + value = module.label8t_context.context +} + +output "label8t_context_tags" { + value = module.label8t_context.tags +} + +output "label8t_id" { + value = module.label8t.id +} + +output "label8t_context" { + value = module.label8t.context +} + +output "label8t_tags" { + value = module.label8t.tags +} diff --git a/.terraform/modules/datadog_integration.core_label/examples/complete/label8u.tf b/.terraform/modules/datadog_integration.core_label/examples/complete/label8u.tf new file mode 100755 index 0000000..499535b --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/complete/label8u.tf @@ -0,0 +1,50 @@ +module "label8u" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "upper" + label_value_case = "upper" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8u_context" { + source = "../../" + + context = module.label8u.context +} + +output "label8u_context_id" { + value = module.label8u_context.id +} + +output "label8u_context_context" { + value = module.label8u_context.context +} + +// debug +output "label8u_context_normalized_context" { + value = module.label8u_context.normalized_context +} + +output "label8u_context_tags" { + value = module.label8u_context.tags +} + +output "label8u_id" { + value = module.label8u.id +} + +output "label8u_context" { + value = module.label8u.context +} + +output "label8u_tags" { + value = module.label8u.tags +} diff --git a/.terraform/modules/datadog_integration.core_label/examples/complete/versions.tf b/.terraform/modules/datadog_integration.core_label/examples/complete/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/examples/complete/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration.core_label/exports/context.tf b/.terraform/modules/datadog_integration.core_label/exports/context.tf new file mode 100755 index 0000000..81f99b4 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/exports/context.tf @@ -0,0 +1,202 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration.core_label/main.tf b/.terraform/modules/datadog_integration.core_label/main.tf new file mode 100755 index 0000000..0deda2b --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/main.tf @@ -0,0 +1,146 @@ +locals { + + defaults = { + label_order = ["namespace", "environment", "stage", "name", "attributes"] + regex_replace_chars = "/[^-a-zA-Z0-9]/" + delimiter = "-" + replacement = "" + id_length_limit = 0 + id_hash_length = 5 + label_key_case = "title" + label_value_case = "lower" + } + + # So far, we have decided not to allow overriding replacement or id_hash_length + replacement = local.defaults.replacement + id_hash_length = local.defaults.id_hash_length + + # The values provided by variables supersede the values inherited from the context object, + # except for tags and attributes which are merged. + input = { + # It would be nice to use coalesce here, but we cannot, because it + # is an error for all the arguments to coalesce to be empty. + enabled = var.enabled == null ? var.context.enabled : var.enabled + namespace = var.namespace == null ? var.context.namespace : var.namespace + environment = var.environment == null ? var.context.environment : var.environment + stage = var.stage == null ? var.context.stage : var.stage + name = var.name == null ? var.context.name : var.name + delimiter = var.delimiter == null ? var.context.delimiter : var.delimiter + # modules tack on attributes (passed by var) to the end of the list (passed by context) + attributes = compact(distinct(concat(coalesce(var.context.attributes, []), coalesce(var.attributes, [])))) + tags = merge(var.context.tags, var.tags) + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + label_order = var.label_order == null ? var.context.label_order : var.label_order + regex_replace_chars = var.regex_replace_chars == null ? var.context.regex_replace_chars : var.regex_replace_chars + id_length_limit = var.id_length_limit == null ? var.context.id_length_limit : var.id_length_limit + label_key_case = var.label_key_case == null ? lookup(var.context, "label_key_case", null) : var.label_key_case + label_value_case = var.label_value_case == null ? lookup(var.context, "label_value_case", null) : var.label_value_case + } + + + enabled = local.input.enabled + regex_replace_chars = coalesce(local.input.regex_replace_chars, local.defaults.regex_replace_chars) + + # string_label_names are names of inputs that are strings (not list of strings) used as labels + string_label_names = ["name", "namespace", "environment", "stage"] + normalized_labels = { for k in local.string_label_names : k => + local.input[k] == null ? "" : replace(local.input[k], local.regex_replace_chars, local.replacement) + } + normalized_attributes = compact(distinct([for v in local.input.attributes : replace(v, local.regex_replace_chars, local.replacement)])) + + formatted_labels = { for k in local.string_label_names : k => local.label_value_case == "none" ? local.normalized_labels[k] : + local.label_value_case == "title" ? title(lower(local.normalized_labels[k])) : + local.label_value_case == "upper" ? upper(local.normalized_labels[k]) : lower(local.normalized_labels[k]) + } + + attributes = compact(distinct([ + for v in local.normalized_attributes : (local.label_value_case == "none" ? v : + local.label_value_case == "title" ? title(lower(v)) : + local.label_value_case == "upper" ? upper(v) : lower(v)) + ])) + + name = local.formatted_labels["name"] + namespace = local.formatted_labels["namespace"] + environment = local.formatted_labels["environment"] + stage = local.formatted_labels["stage"] + + delimiter = local.input.delimiter == null ? local.defaults.delimiter : local.input.delimiter + label_order = local.input.label_order == null ? local.defaults.label_order : coalescelist(local.input.label_order, local.defaults.label_order) + id_length_limit = local.input.id_length_limit == null ? local.defaults.id_length_limit : local.input.id_length_limit + label_key_case = local.input.label_key_case == null ? local.defaults.label_key_case : local.input.label_key_case + label_value_case = local.input.label_value_case == null ? local.defaults.label_value_case : local.input.label_value_case + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + + tags = merge(local.generated_tags, local.input.tags) + + tags_as_list_of_maps = flatten([ + for key in keys(local.tags) : merge( + { + key = key + value = local.tags[key] + }, var.additional_tag_map) + ]) + + tags_context = { + # For AWS we need `Name` to be disambiguated since it has a special meaning + name = local.id + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = local.id_context.attributes + } + + generated_tags = { + for l in keys(local.tags_context) : + local.label_key_case == "upper" ? upper(l) : ( + local.label_key_case == "lower" ? lower(l) : title(lower(l)) + ) => local.tags_context[l] if length(local.tags_context[l]) > 0 + } + + id_context = { + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = join(local.delimiter, local.attributes) + } + + labels = [for l in local.label_order : local.id_context[l] if length(local.id_context[l]) > 0] + + id_full = join(local.delimiter, local.labels) + # Create a truncated ID if needed + delimiter_length = length(local.delimiter) + # Calculate length of normal part of ID, leaving room for delimiter and hash + id_truncated_length_limit = local.id_length_limit - (local.id_hash_length + local.delimiter_length) + # Truncate the ID and ensure a single (not double) trailing delimiter + id_truncated = local.id_truncated_length_limit <= 0 ? "" : "${trimsuffix(substr(local.id_full, 0, local.id_truncated_length_limit), local.delimiter)}${local.delimiter}" + # Support usages that disallow numeric characters. Would prefer tr 0-9 q-z but Terraform does not support it. + id_hash_plus = "${md5(local.id_full)}qrstuvwxyz" + id_hash_case = local.label_value_case == "title" ? title(local.id_hash_plus) : local.label_value_case == "upper" ? upper(local.id_hash_plus) : local.label_value_case == "lower" ? lower(local.id_hash_plus) : local.id_hash_plus + id_hash = replace(local.id_hash_case, local.regex_replace_chars, local.replacement) + # Create the short ID by adding a hash to the end of the truncated ID + id_short = substr("${local.id_truncated}${local.id_hash}", 0, local.id_length_limit) + id = local.id_length_limit != 0 && length(local.id_full) > local.id_length_limit ? local.id_short : local.id_full + + + # Context of this label to pass to other label modules + output_context = { + enabled = local.enabled + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + delimiter = local.delimiter + attributes = local.attributes + tags = local.tags + additional_tag_map = local.additional_tag_map + label_order = local.label_order + regex_replace_chars = local.regex_replace_chars + id_length_limit = local.id_length_limit + label_key_case = local.label_key_case + label_value_case = local.label_value_case + } + +} diff --git a/.terraform/modules/datadog_integration.core_label/outputs.tf b/.terraform/modules/datadog_integration.core_label/outputs.tf new file mode 100755 index 0000000..87ad1be --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/outputs.tf @@ -0,0 +1,88 @@ +output "id" { + value = local.enabled ? local.id : "" + description = "Disambiguated ID restricted to `id_length_limit` characters in total" +} + +output "id_full" { + value = local.enabled ? local.id_full : "" + description = "Disambiguated ID not restricted in length" +} + +output "enabled" { + value = local.enabled + description = "True if module is enabled, false otherwise" +} + +output "namespace" { + value = local.enabled ? local.namespace : "" + description = "Normalized namespace" +} + +output "environment" { + value = local.enabled ? local.environment : "" + description = "Normalized environment" +} + +output "name" { + value = local.enabled ? local.name : "" + description = "Normalized name" +} + +output "stage" { + value = local.enabled ? local.stage : "" + description = "Normalized stage" +} + +output "delimiter" { + value = local.enabled ? local.delimiter : "" + description = "Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes`" +} + +output "attributes" { + value = local.enabled ? local.attributes : [] + description = "List of attributes" +} + +output "tags" { + value = local.enabled ? local.tags : {} + description = "Normalized Tag map" +} + +output "additional_tag_map" { + value = local.additional_tag_map + description = "The merged additional_tag_map" +} + +output "label_order" { + value = local.label_order + description = "The naming order actually used to create the ID" +} + +output "regex_replace_chars" { + value = local.regex_replace_chars + description = "The regex_replace_chars actually used to create the ID" +} + +output "id_length_limit" { + value = local.id_length_limit + description = "The id_length_limit actually used to create the ID, with `0` meaning unlimited" +} + +output "tags_as_list_of_maps" { + value = local.tags_as_list_of_maps + description = "Additional tags as a list of maps, which can be used in several AWS resources" +} + +output "normalized_context" { + value = local.output_context + description = "Normalized context of this module" +} + +output "context" { + value = local.input + description = <<-EOT + Merged but otherwise unmodified input to this module, to be used as context input to other modules. + Note: this version will have null values as defaults, not the values actually used as defaults. +EOT +} + diff --git a/.terraform/modules/datadog_integration.core_label/test/Makefile b/.terraform/modules/datadog_integration.core_label/test/Makefile new file mode 100755 index 0000000..ea15d62 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/test/Makefile @@ -0,0 +1,43 @@ +TEST_HARNESS ?= https://github.com/cloudposse/test-harness.git +TEST_HARNESS_BRANCH ?= master +TEST_HARNESS_PATH = $(realpath .test-harness) +BATS_ARGS ?= --tap +BATS_LOG ?= test.log + +# Define a macro to run the tests +define RUN_TESTS +@echo "Running tests in $(1)" +@cd $(1) && bats $(BATS_ARGS) $(addsuffix .bats,$(addprefix $(TEST_HARNESS_PATH)/test/terraform/,$(TESTS))) +endef + +default: all + +-include Makefile.* + +## Provision the test-harnesss +.test-harness: + [ -d $@ ] || git clone --depth=1 -b $(TEST_HARNESS_BRANCH) $(TEST_HARNESS) $@ + +## Initialize the tests +init: .test-harness + +## Install all dependencies (OS specific) +deps:: + @exit 0 + +## Clean up the test harness +clean: + [ "$(TEST_HARNESS_PATH)" == "/" ] || rm -rf $(TEST_HARNESS_PATH) + +## Run all tests +all: module examples/complete + +## Run basic sanity checks against the module itself +module: export TESTS ?= installed lint get-modules module-pinning get-plugins provider-pinning validate terraform-docs input-descriptions output-descriptions +module: deps + $(call RUN_TESTS, ../) + +## Run tests against example +examples/complete: export TESTS ?= installed lint get-modules get-plugins validate init plan apply +examples/complete: deps + $(call RUN_TESTS, ../$@) diff --git a/.terraform/modules/datadog_integration.core_label/test/Makefile.alpine b/.terraform/modules/datadog_integration.core_label/test/Makefile.alpine new file mode 100755 index 0000000..7925b18 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/test/Makefile.alpine @@ -0,0 +1,5 @@ +ifneq (,$(wildcard /sbin/apk)) +## Install all dependencies for alpine +deps:: init + @apk add --update terraform-docs@cloudposse json2hcl@cloudposse +endif diff --git a/.terraform/modules/datadog_integration.core_label/test/src/Makefile b/.terraform/modules/datadog_integration.core_label/test/src/Makefile new file mode 100755 index 0000000..b772822 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/test/src/Makefile @@ -0,0 +1,30 @@ +export TF_CLI_ARGS_init ?= -get-plugins=true +export TERRAFORM_VERSION ?= $(shell curl -s https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r -M '.current_version' | cut -d. -f1-2) + +.DEFAULT_GOAL : all +.PHONY: all + +## Default target +all: test + +.PHONY : init +## Initialize tests +init: + @exit 0 + +.PHONY : test +## Run tests +test: init + go mod download + go test -v -timeout 60m -run TestExamplesComplete + +## Run tests in docker container +docker/test: + docker run --name terratest --rm -it -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e GITHUB_TOKEN \ + -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" \ + -v $(CURDIR)/../../:/module/ cloudposse/test-harness:latest -C /module/test/src test + +.PHONY : clean +## Clean up files +clean: + rm -rf ../../examples/complete/*.tfstate* diff --git a/.terraform/modules/datadog_integration.core_label/test/src/examples_complete_test.go b/.terraform/modules/datadog_integration.core_label/test/src/examples_complete_test.go new file mode 100755 index 0000000..156e293 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/test/src/examples_complete_test.go @@ -0,0 +1,293 @@ +package test + +import ( + "fmt" + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" + "github.com/qdm12/reprint" + "github.com/stretchr/testify/assert" +) + +type NLContext struct { + AdditionalTagMap map[string]string `json:"additional_tag_map"` + Attributes []string `json:"attributes"` + Delimiter interface{} `json:"delimiter"` + Enabled bool `json:"enabled"` + Environment interface{} `json:"environment"` + LabelOrder []string `json:"label_order"` + Name interface{} `json:"name"` + Namespace interface{} `json:"namespace"` + RegexReplaceChars interface{} `json:"regex_replace_chars"` + Stage interface{} `json:"stage"` + Tags map[string]string `json:"tags"` +} + +// Test the Terraform module in examples/complete using Terratest. +func TestExamplesComplete(t *testing.T) { + t.Parallel() + + terraformOptions := &terraform.Options{ + // The path to where our Terraform code is located + TerraformDir: "../../examples/complete", + Upgrade: true, + } + + // At the end of the test, run `terraform destroy` to clean up any resources that were created + defer terraform.Destroy(t, terraformOptions) + + // This will run `terraform init` and `terraform apply` and fail the test if there are any errors + terraform.InitAndApply(t, terraformOptions) + + expectedLabel1Context := NLContext{ + Enabled: true, + Namespace: "CloudPosse", + Environment: "UAT", + Stage: "build", + Name: "Winston Churchroom", + Attributes: []string{"fire", "water", "earth", "air"}, + Delimiter: "-", + LabelOrder: []string{"name", "environment", "stage", "attributes"}, + Tags: map[string]string{ + "City": "Dublin", + "Environment": "Private", + }, + AdditionalTagMap: map[string]string{}, + } + + var expectedLabel1NormalizedContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel1NormalizedContext) + expectedLabel1NormalizedContext.Namespace = "cloudposse" + expectedLabel1NormalizedContext.Environment = "uat" + expectedLabel1NormalizedContext.Name = "winstonchurchroom" + expectedLabel1NormalizedContext.RegexReplaceChars = "/[^-a-zA-Z0-9]/" + expectedLabel1NormalizedContext.Tags = map[string]string{ + "City": "Dublin", + "Environment": "Private", + "Namespace": "cloudposse", + "Stage": "build", + "Name": "winstonchurchroom-uat-build-fire-water-earth-air", + "Attributes": "fire-water-earth-air", + } + + var label1NormalizedContext, label1Context NLContext + // Run `terraform output` to get the value of an output variable + label1 := terraform.OutputMap(t, terraformOptions, "label1") + label1Tags := terraform.OutputMap(t, terraformOptions, "label1_tags") + terraform.OutputStruct(t, terraformOptions, "label1_normalized_context", &label1NormalizedContext) + terraform.OutputStruct(t, terraformOptions, "label1_context", &label1Context) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1["id"]) + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1Tags["Name"]) + assert.Equal(t, "Dublin", label1Tags["City"]) + assert.Equal(t, "Private", label1Tags["Environment"]) + assert.Equal(t, expectedLabel1NormalizedContext, label1NormalizedContext) + assert.Equal(t, expectedLabel1Context, label1Context) + + label1t1 := terraform.OutputMap(t, terraformOptions, "label1t1") + label1t1Tags := terraform.OutputMap(t, terraformOptions, "label1t1_tags") + assert.Equal(t, "winstonchurchroom-uat-6a0b34", label1t1["id"], + "Extra hash character should be added when trailing delimiter is removed") + assert.Equal(t, label1["id"], label1t1["id_full"], "id_full should not be truncated") + assert.Equal(t, label1t1["id"], label1t1Tags["Name"], "Name tag should match ID") + + label1t2 := terraform.OutputMap(t, terraformOptions, "label1t2") + label1t2Tags := terraform.OutputMap(t, terraformOptions, "label1t2_tags") + assert.Equal(t, "winstonchurchroom-uat-b-6a0b3", label1t2["id"]) + assert.Equal(t, label1t2["id"], label1t2Tags["Name"], "Name tag should match ID") + + // Run `terraform output` to get the value of an output variable + label2 := terraform.OutputMap(t, terraformOptions, "label2") + label2Tags := terraform.OutputMap(t, terraformOptions, "label2_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2["id"]) + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2Tags["Name"]) + assert.Equal(t, "London", label2Tags["City"]) + assert.Equal(t, "Public", label2Tags["Environment"]) + + var expectedLabel3cContext, label3cContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel3cContext) + expectedLabel3cContext.Name = "Starfish" + expectedLabel3cContext.Stage = "release" + expectedLabel3cContext.Delimiter = "." + expectedLabel3cContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3cContext.Tags["Eat"] = "Carrot" + expectedLabel3cContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3c := terraform.OutputMap(t, terraformOptions, "label3c") + label3cTags := terraform.OutputMap(t, terraformOptions, "label3c_tags") + terraform.OutputStruct(t, terraformOptions, "label3c_context", &label3cContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3c["id"]) + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3cTags["Name"]) + assert.Equal(t, expectedLabel3cContext, label3cContext) + + var expectedLabel3nContext, label3nContext NLContext + _ = reprint.FromTo(&expectedLabel1NormalizedContext, &expectedLabel3nContext) + expectedLabel3nContext.Name = "Starfish" + expectedLabel3nContext.Stage = "release" + expectedLabel3nContext.Delimiter = "." + expectedLabel3nContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3nContext.Tags["Eat"] = "Carrot" + expectedLabel3nContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3n := terraform.OutputMap(t, terraformOptions, "label3n") + label3nTags := terraform.OutputMap(t, terraformOptions, "label3n_tags") + terraform.OutputStruct(t, terraformOptions, "label3n_context", &label3nContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3n["id"]) + assert.Equal(t, label1Tags["Name"], label3nTags["Name"], + "Tag from label1 normalized context should overwrite label3n generated tag") + assert.Equal(t, expectedLabel3nContext, label3nContext) + + // Run `terraform output` to get the value of an output variable + label4 := terraform.OutputMap(t, terraformOptions, "label4") + label4Tags := terraform.OutputMap(t, terraformOptions, "label4_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4["id"]) + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4Tags["Name"]) + + // Run `terraform output` to get the value of an output variable + label5 := terraform.OutputMap(t, terraformOptions, "label5") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "", label5["id"]) + + label6f := terraform.OutputMap(t, terraformOptions, "label6f") + label6fTags := terraform.OutputMap(t, terraformOptions, "label6f_tags") + // Test of setting var.label_key_case = "lower", var.label_value_case = "upper" + assert.Equal(t, "CP~UW2~PRD~NULL-LABEL", label6f["id_full"]) + assert.Equal(t, label6f["id_full"], label6f["id"], "id should not be truncated") + assert.Equal(t, label6f["id"], label6fTags["name"], "Name tag should match ID") + + label6t := terraform.OutputMap(t, terraformOptions, "label6t") + label6tTags := terraform.OutputMap(t, terraformOptions, "label6t_tags") + assert.Equal(t, "CPUW2PRDNULL-LABEL", label6t["id_full"]) + assert.NotEqual(t, label6t["id_full"], label6t["id"], "id should be truncated") + assert.Equal(t, label6t["id"], label6tTags["name"], "Name tag should match ID") + assert.Equal(t, label6t["id_length_limit"], fmt.Sprintf("%d", len(label6t["id"])), + "Truncated ID length should equal length limit") + + label7 := terraform.OutputMap(t, terraformOptions, "label7") + assert.Equal(t, "eg-demo-blue-cluster-nodegroup", label7["id"], "var.attributes should be appended after context.attributes") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter=""` returns expected value of id, context id + label8dndID := terraform.Output(t, terraformOptions, "label8dnd_id") + label8dndContextID := terraform.Output(t, terraformOptions, "label8dnd_context_id") + assert.Equal(t, "egdemobluecluster", label8dndID) + assert.Equal(t, label8dndID, label8dndContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter="x"` returns expected value of id, context id + label8dcdID := terraform.Output(t, terraformOptions, "label8dcd_id") + label8dcdContextID := terraform.Output(t, terraformOptions, "label8dcd_context_id") + assert.Equal(t, "egxdemoxbluexcluster", label8dcdID) + assert.Equal(t, label8dcdID, label8dcdContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=lower` returns expected values of id, tags, context tags + label8dExpectedTags := map[string]string{ + "Attributes": "cluster", + "Environment": "demo", + "Name": "eg-demo-blue-cluster", + "Namespace": "eg", + "kubernetes.io/cluster/": "shared", + } + + label8dID := terraform.Output(t, terraformOptions, "label8d_id") + label8dContextID := terraform.Output(t, terraformOptions, "label8d_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8dID) + assert.Equal(t, label8dID, label8dContextID, "ID and context ID should be equal") + + label8dTags := terraform.OutputMap(t, terraformOptions, "label8d_tags") + label8dContextTags := terraform.OutputMap(t, terraformOptions, "label8d_context_tags") + + assert.Exactly(t, label8dExpectedTags, label8dTags, "generated tags are different from expected") + assert.Exactly(t, label8dTags, label8dContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=lower` and `label_value_case=lower` returns expected values of id, tags, context tags + label8lExpectedTags := map[string]string{ + "attributes": "cluster", + "environment": "demo", + "name": "eg-demo-blue-cluster", + "namespace": "eg", + "kubernetes.io/cluster/": "shared", + "upperTEST": "testUPPER", + } + + label8lID := terraform.Output(t, terraformOptions, "label8l_id") + label8lContextID := terraform.Output(t, terraformOptions, "label8l_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8lID) + assert.Equal(t, label8lID, label8lContextID, "ID and context ID should be equal") + + label8lTags := terraform.OutputMap(t, terraformOptions, "label8l_tags") + label8lContextTags := terraform.OutputMap(t, terraformOptions, "label8l_context_tags") + + assert.Exactly(t, label8lExpectedTags, label8lTags, "generated tags are different from expected") + assert.Exactly(t, label8lTags, label8lContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=title` returns expected values of id, tags, context tags + label8tExpectedTags := map[string]string{ + "Attributes": "Eks-Cluster", + "Environment": "Demo", + "Name": "Eg-Demo-Blue-Eks-Cluster", + "Namespace": "Eg", + "kubernetes.io/cluster/": "shared", + } + + label8tID := terraform.Output(t, terraformOptions, "label8t_id") + label8tContextID := terraform.Output(t, terraformOptions, "label8t_context_id") + assert.Equal(t, "Eg-Demo-Blue-Eks-Cluster", label8tID) + assert.Equal(t, label8tID, label8tContextID, "ID and context ID should be equal") + + label8tTags := terraform.OutputMap(t, terraformOptions, "label8t_tags") + label8tContextTags := terraform.OutputMap(t, terraformOptions, "label8t_context_tags") + + assert.Exactly(t, label8tExpectedTags, label8tTags, "generated tags are different from expected") + assert.Exactly(t, label8tTags, label8tContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=upper` and `label_value_case=upper` returns expected values of id, tags, context tags + label8uExpectedTags := map[string]string{ + "ATTRIBUTES": "CLUSTER", + "ENVIRONMENT": "DEMO", + "NAME": "EG-DEMO-BLUE-CLUSTER", + "NAMESPACE": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8uID := terraform.Output(t, terraformOptions, "label8u_id") + label8uContextID := terraform.Output(t, terraformOptions, "label8u_context_id") + assert.Equal(t, "EG-DEMO-BLUE-CLUSTER", label8uID) + assert.Equal(t, label8uID, label8uContextID, "ID and context ID should be equal") + + label8uTags := terraform.OutputMap(t, terraformOptions, "label8u_tags") + label8uContextTags := terraform.OutputMap(t, terraformOptions, "label8u_context_tags") + + assert.Exactly(t, label8uExpectedTags, label8uTags, "generated tags are different from expected") + assert.Exactly(t, label8uTags, label8uContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=none` returns expected values of id, tags, context tags + label8nExpectedTags := map[string]string{ + "Attributes": "eks-ClusteR", + "Environment": "demo", + "Name": "EG-demo-blue-eks-ClusteR", + "Namespace": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8nID := terraform.Output(t, terraformOptions, "label8n_id") + label8nContextID := terraform.Output(t, terraformOptions, "label8n_context_id") + assert.Equal(t, "EG-demo-blue-eks-ClusteR", label8nID) + assert.Equal(t, label8nID, label8nContextID, "ID and context ID should be equal") + + label8nTags := terraform.OutputMap(t, terraformOptions, "label8n_tags") + label8nContextTags := terraform.OutputMap(t, terraformOptions, "label8n_context_tags") + + assert.Exactly(t, label8nExpectedTags, label8nTags, "generated tags are different from expected") + assert.Exactly(t, label8nTags, label8nContextTags, "tags and context tags should be equal") +} diff --git a/.terraform/modules/datadog_integration.core_label/test/src/go.mod b/.terraform/modules/datadog_integration.core_label/test/src/go.mod new file mode 100755 index 0000000..d866541 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/test/src/go.mod @@ -0,0 +1,9 @@ +module github.com/cloudposse/terraform-null-label + +go 1.14 + +require ( + github.com/gruntwork-io/terratest v0.31.1 + github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 + github.com/stretchr/testify v1.6.1 +) diff --git a/.terraform/modules/datadog_integration.core_label/test/src/go.sum b/.terraform/modules/datadog_integration.core_label/test/src/go.sum new file mode 100755 index 0000000..b8d46b1 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/test/src/go.sum @@ -0,0 +1,595 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= +github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.5/go.mod h1:foo3aIXRQ90zFve3r0QiDsrjGDUwWhKl0ZOQy1CT14k= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= +github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200109221225-a4f60165b7a3/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= +github.com/gruntwork-io/terratest v0.31.1 h1:MPGe/5pGgJAIZ/hb+0LM1KyJKSi/QyxSkHoP9/CBhJg= +github.com/gruntwork-io/terratest v0.31.1/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= +github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4= +github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= +github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= +k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= +k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= +k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= +k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= +k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= +k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= +k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= +modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/.terraform/modules/datadog_integration.core_label/variables.tf b/.terraform/modules/datadog_integration.core_label/variables.tf new file mode 100755 index 0000000..40fb268 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/variables.tf @@ -0,0 +1,157 @@ +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} diff --git a/.terraform/modules/datadog_integration.core_label/versions.tf b/.terraform/modules/datadog_integration.core_label/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration.core_label/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds b/.terraform/modules/datadog_integration.forwarder_rds new file mode 160000 index 0000000..6f24262 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds @@ -0,0 +1 @@ +Subproject commit 6f24262652a52a055de711cfee0e3dfac5221e0e diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/LICENSE b/.terraform/modules/datadog_integration.forwarder_rds.this/LICENSE new file mode 100755 index 0000000..c844c70 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017-2020 Cloud Posse, LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/Makefile b/.terraform/modules/datadog_integration.forwarder_rds.this/Makefile new file mode 100755 index 0000000..97d8087 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/Makefile @@ -0,0 +1,10 @@ +SHELL := /bin/bash + +# List of targets the `readme` target should call before generating the readme +export README_DEPS ?= docs/targets.md docs/terraform.md + +-include $(shell curl -sSL -o .build-harness "https://git.io/build-harness"; echo .build-harness) + +## Lint terraform code +lint: + $(SELF) terraform/install terraform/get-modules terraform/get-plugins terraform/lint terraform/validate diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/README.md b/.terraform/modules/datadog_integration.forwarder_rds.this/README.md new file mode 100755 index 0000000..32950e4 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/README.md @@ -0,0 +1,938 @@ + +# terraform-null-label [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-null-label.svg)](https://github.com/cloudposse/terraform-null-label/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) + + +[![README Header][readme_header_img]][readme_header_link] + +[![Cloud Posse][logo]](https://cpco.io/homepage) + + + +Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + +This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. +However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). +So if you prefer the term `stage` to `environment` +you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. +- If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. +- If you want the attributes in a different order, you can specify that, too, with the `label_order` list. +- You can set a maximum length for the name, and the module will create a unique name that fits within that length. +- You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. +- The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + +It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. +For example, if you have 10 instances, there should be 10 different labels. +However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + +All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + +**NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. +With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + +- Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. +- Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. +- Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. + + +--- + +This project is part of our comprehensive ["SweetOps"](https://cpco.io/sweetops) approach towards DevOps. +[][share_email] +[][share_googleplus] +[][share_facebook] +[][share_reddit] +[][share_linkedin] +[][share_twitter] + + +[![Terraform Open Source Modules](https://docs.cloudposse.com/images/terraform-open-source-modules.svg)][terraform_modules] + + + +It's 100% Open Source and licensed under the [APACHE2](LICENSE). + + + + + + + +We literally have [*hundreds of terraform modules*][terraform_modules] that are Open Source and well-maintained. Check them out! + + + + + + + +## Security & Compliance [](https://bridgecrew.io/) + +Security scanning is graciously provided by Bridgecrew. Bridgecrew is the leading fully hosted, cloud-native solution providing continuous Terraform security and compliance. + +| Benchmark | Description | +|--------|---------------| +| [![Infrastructure Security](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/general)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=INFRASTRUCTURE+SECURITY) | Infrastructure Security Compliance | +| [![CIS KUBERNETES](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_kubernetes)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+KUBERNETES+V1.5) | Center for Internet Security, KUBERNETES Compliance | +| [![CIS AWS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_aws)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AWS+V1.2) | Center for Internet Security, AWS Compliance | +| [![CIS AZURE](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_azure)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AZURE+V1.1) | Center for Internet Security, AZURE Compliance | +| [![PCI-DSS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/pci)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=PCI-DSS+V3.2) | Payment Card Industry Data Security Standards Compliance | +| [![NIST-800-53](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/nist)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=NIST-800-53) | National Institute of Standards and Technology Compliance | +| [![ISO27001](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/iso)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=ISO27001) | Information Security Management System, ISO/IEC 27001 Compliance | +| [![SOC2](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/soc2)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=SOC2)| Service Organization Control 2 Compliance | +| [![CIS GCP](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_gcp)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+GCP+V1.1) | Center for Internet Security, GCP Compliance | +| [![HIPAA](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/hipaa)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=HIPAA) | Health Insurance Portability and Accountability Compliance | + + + +## Usage + + +**IMPORTANT:** We do not pin modules to versions in our examples because of the +difficulty of keeping the versions in the documentation in sync with the latest released versions. +We highly recommend that in your code you pin the version to the exact version you are +using so that your infrastructure remains stable, and update versions in a +systematic way so that they do not catch you by surprise. + +Also, because of a bug in the Terraform registry ([hashicorp/terraform#21417](https://github.com/hashicorp/terraform/issues/21417)), +the registry shows many of our inputs as required when in fact they are optional. +The table below correctly indicates which inputs are required. + + +### Defaults + +Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. +The context object is a single object that contains all the input values for `terraform-null-label`. +However, each input value can also be specified individually by name as a standard Terraform variable, +and the value of those variables, when set to something other than `null`, will override the value +in the context object. In order to allow chaining of these objects, where the context object input to one +module is transformed and passed to the next module, all the variables default to `null` or empty collections. +The actual default values used when nothing is explicitly set are describe in the documentation below. + +For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, +`terraform-null-label` will actually use the default delimiter `-` (hyphen). + +A non-obvious but intentional consequence of this design is that once a module sets a non-default value, +future modules in the chain cannot reset the value back to the original default. Insted, the new setting +becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, +so once a tag is added, it will remain in the tag set and cannot be removed, although its value can +be overwritten. + +### Simple Example + +```hcl +module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} +``` + +This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` +(you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + +Now reference the label when creating an instance: + +```hcl +resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags +} +``` + +Or define a security group: + +```hcl +resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} +``` + + +### Advanced Example + +Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + +```hcl +module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] +} + +module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] +} +``` + +
+ +### Advanced Example 2 + +Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + +```hcl +tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } +] +``` + +Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + +```hcl +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} +``` + +
+ +### Advanced Example 3 + +See [complete example](./examples/complete) for even more examples. + +This example shows how you can pass the `context` output of one label module to the next label_module, +allowing you to create one label that has the base set of values, and then creating every extra label +as a derivative of that. + +
Click to show + +```hcl +module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} +``` + +This creates label outputs like this: + +```hcl +label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" +} +label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } +} +label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } +} +label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" +} +label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" +} +label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } +} +label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" +} +label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, +] +label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" +} +label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } +} +label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } +} +label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" +} + +``` + +
+ + + + + + + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + + + + +## Share the Love + +Like this project? Please give it a ★ on [our GitHub](https://github.com/cloudposse/terraform-null-label)! (it helps us **a lot**) + +Are you using this project or any of our other projects? Consider [leaving a testimonial][testimonial]. =) + + +## Related Projects + +Check out these related projects. + +- [terraform-terraform-label](https://github.com/cloudposse/terraform-terraform-label) - Terraform Module to define a consistent naming convention by (namespace, environment, stage, name, [attributes]) + + + +## Help + +**Got a question?** We got answers. + +File a GitHub [issue](https://github.com/cloudposse/terraform-null-label/issues), send us an [email][email] or join our [Slack Community][slack]. + +[![README Commercial Support][readme_commercial_support_img]][readme_commercial_support_link] + +## DevOps Accelerator for Startups + + +We are a [**DevOps Accelerator**][commercial_support]. We'll help you build your cloud infrastructure from the ground up so you can own it. Then we'll show you how to operate it and stick around for as long as you need us. + +[![Learn More](https://img.shields.io/badge/learn%20more-success.svg?style=for-the-badge)][commercial_support] + +Work directly with our team of DevOps experts via email, slack, and video conferencing. + +We deliver 10x the value for a fraction of the cost of a full-time engineer. Our track record is not even funny. If you want things done right and you need it done FAST, then we're your best bet. + +- **Reference Architecture.** You'll get everything you need from the ground up built using 100% infrastructure as code. +- **Release Engineering.** You'll have end-to-end CI/CD with unlimited staging environments. +- **Site Reliability Engineering.** You'll have total visibility into your apps and microservices. +- **Security Baseline.** You'll have built-in governance with accountability and audit logs for all changes. +- **GitOps.** You'll be able to operate your infrastructure via Pull Requests. +- **Training.** You'll receive hands-on training so your team can operate what we build. +- **Questions.** You'll have a direct line of communication between our teams via a Shared Slack channel. +- **Troubleshooting.** You'll get help to triage when things aren't working. +- **Code Reviews.** You'll receive constructive feedback on Pull Requests. +- **Bug Fixes.** We'll rapidly work with you to fix any bugs in our projects. + +## Slack Community + +Join our [Open Source Community][slack] on Slack. It's **FREE** for everyone! Our "SweetOps" community is where you get to talk with others who share a similar vision for how to rollout and manage infrastructure. This is the best place to talk shop, ask questions, solicit feedback, and work together as a community to build totally *sweet* infrastructure. + +## Discourse Forums + +Participate in our [Discourse Forums][discourse]. Here you'll find answers to commonly asked questions. Most questions will be related to the enormous number of projects we support on our GitHub. Come here to collaborate on answers, find solutions, and get ideas about the products and services we value. It only takes a minute to get started! Just sign in with SSO using your GitHub account. + +## Newsletter + +Sign up for [our newsletter][newsletter] that covers everything on our technology radar. Receive updates on what we're up to on GitHub as well as awesome new projects we discover. + +## Office Hours + +[Join us every Wednesday via Zoom][office_hours] for our weekly "Lunch & Learn" sessions. It's **FREE** for everyone! + +[![zoom](https://img.cloudposse.com/fit-in/200x200/https://cloudposse.com/wp-content/uploads/2019/08/Powered-by-Zoom.png")][office_hours] + +## Contributing + +### Bug Reports & Feature Requests + +Please use the [issue tracker](https://github.com/cloudposse/terraform-null-label/issues) to report any bugs or file feature requests. + +### Developing + +If you are interested in being a contributor and want to get involved in developing this project or [help out](https://cpco.io/help-out) with our other projects, we would love to hear from you! Shoot us an [email][email]. + +In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. + + 1. **Fork** the repo on GitHub + 2. **Clone** the project to your own machine + 3. **Commit** changes to your own branch + 4. **Push** your work back up to your fork + 5. Submit a **Pull Request** so that we can review your changes + +**NOTE:** Be sure to merge the latest changes from "upstream" before making a pull request! + + +## Copyright + +Copyright © 2017-2021 [Cloud Posse, LLC](https://cpco.io/copyright) + + + +## License + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +See [LICENSE](LICENSE) for full details. + +```text +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +``` + + + + + + + + + +## Trademarks + +All other trademarks referenced herein are the property of their respective owners. + +## About + +This project is maintained and funded by [Cloud Posse, LLC][website]. Like it? Please let us know by [leaving a testimonial][testimonial]! + +[![Cloud Posse][logo]][website] + +We're a [DevOps Professional Services][hire] company based in Los Angeles, CA. We ❤️ [Open Source Software][we_love_open_source]. + +We offer [paid support][commercial_support] on all of our projects. + +Check out [our other projects][github], [follow us on twitter][twitter], [apply for a job][jobs], or [hire us][hire] to help with your cloud strategy and implementation. + + + +### Contributors + + +| [![Erik Osterman][osterman_avatar]][osterman_homepage]
[Erik Osterman][osterman_homepage] | [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]
[Andriy Knysh][aknysh_homepage] | [![Igor Rodionov][goruha_avatar]][goruha_homepage]
[Igor Rodionov][goruha_homepage] | [![Sergey Vasilyev][s2504s_avatar]][s2504s_homepage]
[Sergey Vasilyev][s2504s_homepage] | [![Michael Pereira][MichaelPereira_avatar]][MichaelPereira_homepage]
[Michael Pereira][MichaelPereira_homepage] | [![Jamie Nelson][Jamie-BitFlight_avatar]][Jamie-BitFlight_homepage]
[Jamie Nelson][Jamie-BitFlight_homepage] | [![Vladimir][SweetOps_avatar]][SweetOps_homepage]
[Vladimir][SweetOps_homepage] | [![Daren Desjardins][darend_avatar]][darend_homepage]
[Daren Desjardins][darend_homepage] | [![Maarten van der Hoef][maartenvanderhoef_avatar]][maartenvanderhoef_homepage]
[Maarten van der Hoef][maartenvanderhoef_homepage] | [![Adam Tibbing][tibbing_avatar]][tibbing_homepage]
[Adam Tibbing][tibbing_homepage] | +|---|---|---|---|---|---|---|---|---|---| + + + [osterman_homepage]: https://github.com/osterman + [osterman_avatar]: https://img.cloudposse.com/150x150/https://github.com/osterman.png + [aknysh_homepage]: https://github.com/aknysh + [aknysh_avatar]: https://img.cloudposse.com/150x150/https://github.com/aknysh.png + [goruha_homepage]: https://github.com/goruha + [goruha_avatar]: https://img.cloudposse.com/150x150/https://github.com/goruha.png + [s2504s_homepage]: https://github.com/s2504s + [s2504s_avatar]: https://img.cloudposse.com/150x150/https://github.com/s2504s.png + [MichaelPereira_homepage]: https://github.com/MichaelPereira + [MichaelPereira_avatar]: https://img.cloudposse.com/150x150/https://github.com/MichaelPereira.png + [Jamie-BitFlight_homepage]: https://github.com/Jamie-BitFlight + [Jamie-BitFlight_avatar]: https://img.cloudposse.com/150x150/https://github.com/Jamie-BitFlight.png + [SweetOps_homepage]: https://github.com/SweetOps + [SweetOps_avatar]: https://img.cloudposse.com/150x150/https://github.com/SweetOps.png + [darend_homepage]: https://github.com/darend + [darend_avatar]: https://img.cloudposse.com/150x150/https://github.com/darend.png + [maartenvanderhoef_homepage]: https://github.com/maartenvanderhoef + [maartenvanderhoef_avatar]: https://img.cloudposse.com/150x150/https://github.com/maartenvanderhoef.png + [tibbing_homepage]: https://github.com/tibbing + [tibbing_avatar]: https://img.cloudposse.com/150x150/https://github.com/tibbing.png + +[![README Footer][readme_footer_img]][readme_footer_link] +[![Beacon][beacon]][website] + + [logo]: https://cloudposse.com/logo-300x69.svg + [docs]: https://cpco.io/docs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=docs + [website]: https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=website + [github]: https://cpco.io/github?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=github + [jobs]: https://cpco.io/jobs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=jobs + [hire]: https://cpco.io/hire?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=hire + [slack]: https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=slack + [linkedin]: https://cpco.io/linkedin?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=linkedin + [twitter]: https://cpco.io/twitter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=twitter + [testimonial]: https://cpco.io/leave-testimonial?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=testimonial + [office_hours]: https://cloudposse.com/office-hours?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=office_hours + [newsletter]: https://cpco.io/newsletter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=newsletter + [discourse]: https://ask.sweetops.com/?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=discourse + [email]: https://cpco.io/email?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=email + [commercial_support]: https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=commercial_support + [we_love_open_source]: https://cpco.io/we-love-open-source?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=we_love_open_source + [terraform_modules]: https://cpco.io/terraform-modules?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=terraform_modules + [readme_header_img]: https://cloudposse.com/readme/header/img + [readme_header_link]: https://cloudposse.com/readme/header/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_header_link + [readme_footer_img]: https://cloudposse.com/readme/footer/img + [readme_footer_link]: https://cloudposse.com/readme/footer/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_footer_link + [readme_commercial_support_img]: https://cloudposse.com/readme/commercial-support/img + [readme_commercial_support_link]: https://cloudposse.com/readme/commercial-support/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_commercial_support_link + [share_twitter]: https://twitter.com/intent/tweet/?text=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_linkedin]: https://www.linkedin.com/shareArticle?mini=true&title=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_reddit]: https://reddit.com/submit/?url=https://github.com/cloudposse/terraform-null-label + [share_facebook]: https://facebook.com/sharer/sharer.php?u=https://github.com/cloudposse/terraform-null-label + [share_googleplus]: https://plus.google.com/share?url=https://github.com/cloudposse/terraform-null-label + [share_email]: mailto:?subject=terraform-null-label&body=https://github.com/cloudposse/terraform-null-label + [beacon]: https://ga-beacon.cloudposse.com/UA-76589703-4/cloudposse/terraform-null-label?pixel&cs=github&cm=readme&an=terraform-null-label diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/README.yaml b/.terraform/modules/datadog_integration.forwarder_rds.this/README.yaml new file mode 100755 index 0000000..42bdb84 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/README.yaml @@ -0,0 +1,618 @@ +name: terraform-null-label +tags: +- aws +- terraform +- terraform-modules +- naming-convention +- name +- namespace +- stage +categories: +- terraform-modules/supported +license: APACHE2 +github_repo: cloudposse/terraform-null-label +badges: +- name: Latest Release + image: https://img.shields.io/github/release/cloudposse/terraform-null-label.svg + url: https://github.com/cloudposse/terraform-null-label/releases/latest +- name: Slack Community + image: https://slack.cloudposse.com/badge.svg + url: https://slack.cloudposse.com +related: +- name: terraform-terraform-label + description: Terraform Module to define a consistent naming convention by (namespace, + environment, stage, name, [attributes]) + url: https://github.com/cloudposse/terraform-terraform-label +description: |- + Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + + This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. + However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). + So if you prefer the term `stage` to `environment` + you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. + - If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. + - If you want the attributes in a different order, you can specify that, too, with the `label_order` list. + - You can set a maximum length for the name, and the module will create a unique name that fits within that length. + - You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. + - The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + + It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. + For example, if you have 10 instances, there should be 10 different labels. + However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + + All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + + **NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. + With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + + - Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. + - Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. + - Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. +usage: |- + ### Defaults + + Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. + The context object is a single object that contains all the input values for `terraform-null-label`. + However, each input value can also be specified individually by name as a standard Terraform variable, + and the value of those variables, when set to something other than `null`, will override the value + in the context object. In order to allow chaining of these objects, where the context object input to one + module is transformed and passed to the next module, all the variables default to `null` or empty collections. + The actual default values used when nothing is explicitly set are describe in the documentation below. + + For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, + `terraform-null-label` will actually use the default delimiter `-` (hyphen). + + A non-obvious but intentional consequence of this design is that once a module sets a non-default value, + future modules in the chain cannot reset the value back to the original default. Insted, the new setting + becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, + so once a tag is added, it will remain in the tag set and cannot be removed, although its value can + be overwritten. + + ### Simple Example + + ```hcl + module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + ``` + + This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` + (you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + + Now reference the label when creating an instance: + + ```hcl + resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags + } + ``` + + Or define a security group: + + ```hcl + resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + } + ``` + + + ### Advanced Example + + Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + + ```hcl + module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] + } + + module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] + } + ``` + +
+ + ### Advanced Example 2 + + Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + + ```hcl + tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } + ] + ``` + + Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + + ```hcl + ################################ + # terraform-null-label example # + ################################ + module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } + } + + ####################### + # Launch template # + ####################### + resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } + } + + ###################### + # Autoscaling group # + ###################### + resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps + } + ``` + +
+ + ### Advanced Example 3 + + See [complete example](./examples/complete) for even more examples. + + This example shows how you can pass the `context` output of one label module to the next label_module, + allowing you to create one label that has the base set of values, and then creating every extra label + as a derivative of that. + +
Click to show + + ```hcl + module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } + } + + module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } + } + + module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } + } + ``` + + This creates label outputs like this: + + ```hcl + label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" + } + label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } + } + label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + } + label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" + } + label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } + } + label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" + } + label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, + ] + label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" + } + label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } + } + label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + } + label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + + ``` + +
+ +include: +- docs/targets.md +- docs/terraform.md +contributors: +- name: Erik Osterman + github: osterman +- name: Andriy Knysh + github: aknysh +- name: Igor Rodionov + github: goruha +- name: Sergey Vasilyev + github: s2504s +- name: Michael Pereira + github: MichaelPereira +- name: Jamie Nelson + github: Jamie-BitFlight +- name: Vladimir + github: SweetOps +- name: Daren Desjardins + github: darend +- name: Maarten van der Hoef + github: maartenvanderhoef +- name: Adam Tibbing + github: tibbing diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/docs/targets.md b/.terraform/modules/datadog_integration.forwarder_rds.this/docs/targets.md new file mode 100755 index 0000000..3dce8b3 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/docs/targets.md @@ -0,0 +1,12 @@ + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/docs/terraform.md b/.terraform/modules/datadog_integration.forwarder_rds.this/docs/terraform.md new file mode 100755 index 0000000..d4f48f4 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/docs/terraform.md @@ -0,0 +1,54 @@ + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars new file mode 100755 index 0000000..f7c725f --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars @@ -0,0 +1,12 @@ +namespace = "eg" +stage = "prod" +name = "app" + +tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" +} + +additional_tag_map = { + propagate_at_launch = "true" +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/autoscalinggroup/context.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/autoscalinggroup/context.tf new file mode 100755 index 0000000..b97f05f --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/autoscalinggroup/context.tf @@ -0,0 +1,216 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/autoscalinggroup/main.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/autoscalinggroup/main.tf new file mode 100755 index 0000000..f0d3aa6 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/autoscalinggroup/main.tf @@ -0,0 +1,104 @@ +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + + context = module.this.context +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template { + id = aws_launch_template.default.id + version = "$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} + +################################ +# Provider # +################################ +provider "aws" { + region = "eu-west-1" + + # Make it faster by skipping unneeded checks here + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +############################################################## +# Data sources to get VPC, subnets and security group details +############################################################## +data "aws_vpc" "default" { + default = true +} + +data "aws_subnet_ids" "all" { + vpc_id = data.aws_vpc.default.id +} + +data "aws_security_group" "default" { + vpc_id = data.aws_vpc.default.id + name = "default" +} + +data "aws_ami" "amazon_linux" { + most_recent = true + + owners = ["amazon"] + + filter { + name = "name" + + values = [ + "amzn-ami-hvm-*-x86_64-gp2", + ] + } + + filter { + name = "owner-alias" + + values = [ + "amazon", + ] + } +} + diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/autoscalinggroup/outputs.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/autoscalinggroup/outputs.tf new file mode 100755 index 0000000..f8fcce5 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/autoscalinggroup/outputs.tf @@ -0,0 +1,12 @@ +# terraform-null-label example used here: Output list of tags applied in each format +output "tags_as_list_of_maps" { + value = module.label.tags_as_list_of_maps +} + +output "tags" { + value = module.label.tags +} + +output "id" { + value = module.label.id +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/autoscalinggroup/versions.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/autoscalinggroup/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/autoscalinggroup/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/complete.auto.tfvars b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/complete.auto.tfvars new file mode 100755 index 0000000..e7bc519 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/complete.auto.tfvars @@ -0,0 +1,10 @@ +namespace = "cp" +environment = "uw2" +stage = "prd" +name = "null-label" + +delimiter = "" +id_length_limit = 6 + +label_key_case = "lower" +label_value_case = "upper" diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/context.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/context.tf new file mode 100755 index 0000000..973d4dc --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/context.tf @@ -0,0 +1,217 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label1.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label1.tf new file mode 100755 index 0000000..8da353b --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label1.tf @@ -0,0 +1,42 @@ +module "label1" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label1" { + value = { + id = module.label1.id + name = module.label1.name + namespace = module.label1.namespace + stage = module.label1.stage + attributes = module.label1.attributes + delimiter = module.label1.delimiter + } +} + +output "label1_tags" { + value = module.label1.tags +} + +output "label1_context" { + value = module.label1.context +} + +output "label1_normalized_context" { + value = module.label1.normalized_context +} + + + diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label1t1.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label1t1.tf new file mode 100755 index 0000000..2bcb362 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label1t1.tf @@ -0,0 +1,18 @@ +module "label1t1" { + source = "../../" + + id_length_limit = 28 + + context = module.label1.context +} + +output "label1t1" { + value = { + id = module.label1t1.id + id_full = module.label1t1.id_full + } +} + +output "label1t1_tags" { + value = module.label1t1.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label1t2.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label1t2.tf new file mode 100755 index 0000000..5df651e --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label1t2.tf @@ -0,0 +1,18 @@ +module "label1t2" { + source = "../../" + + id_length_limit = 29 + + context = module.label1.context +} + +output "label1t2" { + value = { + id = module.label1t2.id + id_full = module.label1t2.id_full + } +} + +output "label1t2_tags" { + value = module.label1t2.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label2.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label2.tf new file mode 100755 index 0000000..faf7450 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label2.tf @@ -0,0 +1,42 @@ +module "label2" { + source = "../../" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + regex_replace_chars = "/[^a-zA-Z0-9-+]/" + + additional_tag_map = { + propagate_at_launch = "true" + additional_tag = "yes" + } + + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +output "label2" { + value = { + id = module.label2.id + name = module.label2.name + namespace = module.label2.namespace + stage = module.label2.stage + attributes = module.label2.attributes + delimiter = module.label2.delimiter + } +} + +output "label2_tags" { + value = module.label2.tags +} + +output "label2_tags_as_list_of_maps" { + value = module.label2.tags_as_list_of_maps +} + +output "label2_context" { + value = module.label2.context +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label3c.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label3c.tf new file mode 100755 index 0000000..338a636 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label3c.tf @@ -0,0 +1,36 @@ +module "label3c" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3c" { + value = { + id = module.label3c.id + name = module.label3c.name + namespace = module.label3c.namespace + stage = module.label3c.stage + attributes = module.label3c.attributes + delimiter = module.label3c.delimiter + } +} + +output "label3c_tags" { + value = module.label3c.tags +} + +output "label3c_context" { + value = module.label3c.context +} + +output "label3c_normalized_context" { + value = module.label3c.normalized_context +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label3n.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label3n.tf new file mode 100755 index 0000000..ca51282 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label3n.tf @@ -0,0 +1,36 @@ +module "label3n" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.normalized_context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3n" { + value = { + id = module.label3n.id + name = module.label3n.name + namespace = module.label3n.namespace + stage = module.label3n.stage + attributes = module.label3n.attributes + delimiter = module.label3n.delimiter + } +} + +output "label3n_tags" { + value = module.label3n.tags +} + +output "label3n_context" { + value = module.label3n.context +} + +output "label3n_normalized_context" { + value = module.label3n.normalized_context +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label4.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label4.tf new file mode 100755 index 0000000..74e3ca1 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label4.tf @@ -0,0 +1,34 @@ +module "label4" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + name = "Example Cluster" + attributes = ["big", "fat", "honking", "cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label4" { + value = { + id = module.label4.id + name = module.label4.name + namespace = module.label4.namespace + stage = module.label4.stage + attributes = module.label4.attributes + delimiter = module.label4.delimiter + } +} + +output "label4_tags" { + value = module.label4.tags +} + +output "label4_context" { + value = module.label4.context +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label5.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label5.tf new file mode 100755 index 0000000..0f0a76e --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label5.tf @@ -0,0 +1,33 @@ +module "label5" { + source = "../../" + enabled = false + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + } +} + +output "label5" { + value = { + id = module.label5.id + name = module.label5.name + namespace = module.label5.namespace + stage = module.label5.stage + attributes = module.label5.attributes + delimiter = module.label5.delimiter + } +} + +output "label5_tags" { + value = module.label5.tags +} + +output "label5_context" { + value = module.label5.context +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label6f.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label6f.tf new file mode 100755 index 0000000..1ce1bab --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label6f.tf @@ -0,0 +1,20 @@ +module "label6f" { + source = "../../" + + delimiter = "~" + id_length_limit = 0 + + # Use values from tfvars + context = module.this.context +} + +output "label6f" { + value = { + id = module.label6f.id + id_full = module.label6f.id_full + } +} + +output "label6f_tags" { + value = module.label6f.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label6t.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label6t.tf new file mode 100755 index 0000000..b5d9bc1 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label6t.tf @@ -0,0 +1,19 @@ +module "label6t" { + source = "../../" + + # Use values from tfvars, + # specifically: complete.auto.tfvars + context = module.this.context +} + +output "label6t" { + value = { + id = module.label6t.id + id_full = module.label6t.id_full + id_length_limit = module.this.context.id_length_limit + } +} + +output "label6t_tags" { + value = module.label6t.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label7.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label7.tf new file mode 100755 index 0000000..bb365d4 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label7.tf @@ -0,0 +1,44 @@ +module "label7a" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + } +} + +module "label7" { + source = "../../" + + attributes = ["nodegroup"] + + context = module.label7a.context +} + + +output "label7" { + value = { + id = module.label7.id + name = module.label7.name + namespace = module.label7.namespace + stage = module.label7.stage + attributes = module.label7.attributes + delimiter = module.label7.delimiter + } +} + +output "label7_id" { + value = module.label7.id +} + +output "label7_attributes" { + value = module.label7.attributes +} + +output "label7_context" { + value = module.label7.context +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label8d.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label8d.tf new file mode 100755 index 0000000..4252419 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label8d.tf @@ -0,0 +1,44 @@ +module "label8d" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8d_context" { + source = "../../" + + context = module.label8d.context +} + +output "label8d_context_id" { + value = module.label8d_context.id +} + +output "label8d_context_context" { + value = module.label8d_context.context +} + +output "label8d_context_tags" { + value = module.label8d_context.tags +} + +output "label8d_id" { + value = module.label8d.id +} + +output "label8d_context" { + value = module.label8d.context +} + +output "label8d_tags" { + value = module.label8d.tags +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label8dcd.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label8dcd.tf new file mode 100755 index 0000000..ccdae21 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label8dcd.tf @@ -0,0 +1,24 @@ +module "label8dcd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "x" +} + +module "label8dcd_context" { + source = "../../" + + context = module.label8dcd.context +} + +output "label8dcd_context_id" { + value = module.label8dcd_context.id +} + +output "label8dcd_id" { + value = module.label8dcd.id +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label8dnd.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label8dnd.tf new file mode 100755 index 0000000..2edb378 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label8dnd.tf @@ -0,0 +1,24 @@ +module "label8dnd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "" +} + +module "label8dnd_context" { + source = "../../" + + context = module.label8dnd.context +} + +output "label8dnd_context_id" { + value = module.label8dnd_context.id +} + +output "label8dnd_id" { + value = module.label8dnd.id +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label8l.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label8l.tf new file mode 100755 index 0000000..7462f9e --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label8l.tf @@ -0,0 +1,46 @@ +module "label8l" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "lower" + label_value_case = "lower" + + tags = { + "kubernetes.io/cluster/" = "shared" + "upperTEST" = "testUPPER" + } +} + +module "label8l_context" { + source = "../../" + + context = module.label8l.context +} + +output "label8l_context_id" { + value = module.label8l_context.id +} + +output "label8l_context_context" { + value = module.label8l_context.context +} + +output "label8l_context_tags" { + value = module.label8l_context.tags +} + +output "label8l_id" { + value = module.label8l.id +} + +output "label8l_context" { + value = module.label8l.context +} + +output "label8l_tags" { + value = module.label8l.tags +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label8n.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label8n.tf new file mode 100755 index 0000000..fd4ad57 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label8n.tf @@ -0,0 +1,45 @@ +module "label8n" { + source = "../../" + + enabled = true + namespace = "EG" + environment = "demo" + name = "blue" + attributes = ["eks", "ClusteR"] + delimiter = "-" + label_value_case = "none" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8n_context" { + source = "../../" + + context = module.label8n.context +} + +output "label8n_context_id" { + value = module.label8n_context.id +} + +output "label8n_context_context" { + value = module.label8n_context.context +} + +output "label8n_context_tags" { + value = module.label8n_context.tags +} + +output "label8n_id" { + value = module.label8n.id +} + +output "label8n_context" { + value = module.label8n.context +} + +output "label8n_tags" { + value = module.label8n.tags +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label8t.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label8t.tf new file mode 100755 index 0000000..cb54c7a --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label8t.tf @@ -0,0 +1,45 @@ +module "label8t" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["EKS", "cluster"] + delimiter = "-" + label_key_case = "title" + label_value_case = "title" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8t_context" { + source = "../../" + + context = module.label8t.context +} + +output "label8t_context_id" { + value = module.label8t_context.id +} + +output "label8t_context_context" { + value = module.label8t_context.context +} + +output "label8t_context_tags" { + value = module.label8t_context.tags +} + +output "label8t_id" { + value = module.label8t.id +} + +output "label8t_context" { + value = module.label8t.context +} + +output "label8t_tags" { + value = module.label8t.tags +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label8u.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label8u.tf new file mode 100755 index 0000000..499535b --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/label8u.tf @@ -0,0 +1,50 @@ +module "label8u" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "upper" + label_value_case = "upper" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8u_context" { + source = "../../" + + context = module.label8u.context +} + +output "label8u_context_id" { + value = module.label8u_context.id +} + +output "label8u_context_context" { + value = module.label8u_context.context +} + +// debug +output "label8u_context_normalized_context" { + value = module.label8u_context.normalized_context +} + +output "label8u_context_tags" { + value = module.label8u_context.tags +} + +output "label8u_id" { + value = module.label8u.id +} + +output "label8u_context" { + value = module.label8u.context +} + +output "label8u_tags" { + value = module.label8u.tags +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/versions.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/examples/complete/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/exports/context.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/exports/context.tf new file mode 100755 index 0000000..81f99b4 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/exports/context.tf @@ -0,0 +1,202 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/main.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/main.tf new file mode 100755 index 0000000..0deda2b --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/main.tf @@ -0,0 +1,146 @@ +locals { + + defaults = { + label_order = ["namespace", "environment", "stage", "name", "attributes"] + regex_replace_chars = "/[^-a-zA-Z0-9]/" + delimiter = "-" + replacement = "" + id_length_limit = 0 + id_hash_length = 5 + label_key_case = "title" + label_value_case = "lower" + } + + # So far, we have decided not to allow overriding replacement or id_hash_length + replacement = local.defaults.replacement + id_hash_length = local.defaults.id_hash_length + + # The values provided by variables supersede the values inherited from the context object, + # except for tags and attributes which are merged. + input = { + # It would be nice to use coalesce here, but we cannot, because it + # is an error for all the arguments to coalesce to be empty. + enabled = var.enabled == null ? var.context.enabled : var.enabled + namespace = var.namespace == null ? var.context.namespace : var.namespace + environment = var.environment == null ? var.context.environment : var.environment + stage = var.stage == null ? var.context.stage : var.stage + name = var.name == null ? var.context.name : var.name + delimiter = var.delimiter == null ? var.context.delimiter : var.delimiter + # modules tack on attributes (passed by var) to the end of the list (passed by context) + attributes = compact(distinct(concat(coalesce(var.context.attributes, []), coalesce(var.attributes, [])))) + tags = merge(var.context.tags, var.tags) + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + label_order = var.label_order == null ? var.context.label_order : var.label_order + regex_replace_chars = var.regex_replace_chars == null ? var.context.regex_replace_chars : var.regex_replace_chars + id_length_limit = var.id_length_limit == null ? var.context.id_length_limit : var.id_length_limit + label_key_case = var.label_key_case == null ? lookup(var.context, "label_key_case", null) : var.label_key_case + label_value_case = var.label_value_case == null ? lookup(var.context, "label_value_case", null) : var.label_value_case + } + + + enabled = local.input.enabled + regex_replace_chars = coalesce(local.input.regex_replace_chars, local.defaults.regex_replace_chars) + + # string_label_names are names of inputs that are strings (not list of strings) used as labels + string_label_names = ["name", "namespace", "environment", "stage"] + normalized_labels = { for k in local.string_label_names : k => + local.input[k] == null ? "" : replace(local.input[k], local.regex_replace_chars, local.replacement) + } + normalized_attributes = compact(distinct([for v in local.input.attributes : replace(v, local.regex_replace_chars, local.replacement)])) + + formatted_labels = { for k in local.string_label_names : k => local.label_value_case == "none" ? local.normalized_labels[k] : + local.label_value_case == "title" ? title(lower(local.normalized_labels[k])) : + local.label_value_case == "upper" ? upper(local.normalized_labels[k]) : lower(local.normalized_labels[k]) + } + + attributes = compact(distinct([ + for v in local.normalized_attributes : (local.label_value_case == "none" ? v : + local.label_value_case == "title" ? title(lower(v)) : + local.label_value_case == "upper" ? upper(v) : lower(v)) + ])) + + name = local.formatted_labels["name"] + namespace = local.formatted_labels["namespace"] + environment = local.formatted_labels["environment"] + stage = local.formatted_labels["stage"] + + delimiter = local.input.delimiter == null ? local.defaults.delimiter : local.input.delimiter + label_order = local.input.label_order == null ? local.defaults.label_order : coalescelist(local.input.label_order, local.defaults.label_order) + id_length_limit = local.input.id_length_limit == null ? local.defaults.id_length_limit : local.input.id_length_limit + label_key_case = local.input.label_key_case == null ? local.defaults.label_key_case : local.input.label_key_case + label_value_case = local.input.label_value_case == null ? local.defaults.label_value_case : local.input.label_value_case + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + + tags = merge(local.generated_tags, local.input.tags) + + tags_as_list_of_maps = flatten([ + for key in keys(local.tags) : merge( + { + key = key + value = local.tags[key] + }, var.additional_tag_map) + ]) + + tags_context = { + # For AWS we need `Name` to be disambiguated since it has a special meaning + name = local.id + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = local.id_context.attributes + } + + generated_tags = { + for l in keys(local.tags_context) : + local.label_key_case == "upper" ? upper(l) : ( + local.label_key_case == "lower" ? lower(l) : title(lower(l)) + ) => local.tags_context[l] if length(local.tags_context[l]) > 0 + } + + id_context = { + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = join(local.delimiter, local.attributes) + } + + labels = [for l in local.label_order : local.id_context[l] if length(local.id_context[l]) > 0] + + id_full = join(local.delimiter, local.labels) + # Create a truncated ID if needed + delimiter_length = length(local.delimiter) + # Calculate length of normal part of ID, leaving room for delimiter and hash + id_truncated_length_limit = local.id_length_limit - (local.id_hash_length + local.delimiter_length) + # Truncate the ID and ensure a single (not double) trailing delimiter + id_truncated = local.id_truncated_length_limit <= 0 ? "" : "${trimsuffix(substr(local.id_full, 0, local.id_truncated_length_limit), local.delimiter)}${local.delimiter}" + # Support usages that disallow numeric characters. Would prefer tr 0-9 q-z but Terraform does not support it. + id_hash_plus = "${md5(local.id_full)}qrstuvwxyz" + id_hash_case = local.label_value_case == "title" ? title(local.id_hash_plus) : local.label_value_case == "upper" ? upper(local.id_hash_plus) : local.label_value_case == "lower" ? lower(local.id_hash_plus) : local.id_hash_plus + id_hash = replace(local.id_hash_case, local.regex_replace_chars, local.replacement) + # Create the short ID by adding a hash to the end of the truncated ID + id_short = substr("${local.id_truncated}${local.id_hash}", 0, local.id_length_limit) + id = local.id_length_limit != 0 && length(local.id_full) > local.id_length_limit ? local.id_short : local.id_full + + + # Context of this label to pass to other label modules + output_context = { + enabled = local.enabled + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + delimiter = local.delimiter + attributes = local.attributes + tags = local.tags + additional_tag_map = local.additional_tag_map + label_order = local.label_order + regex_replace_chars = local.regex_replace_chars + id_length_limit = local.id_length_limit + label_key_case = local.label_key_case + label_value_case = local.label_value_case + } + +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/outputs.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/outputs.tf new file mode 100755 index 0000000..87ad1be --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/outputs.tf @@ -0,0 +1,88 @@ +output "id" { + value = local.enabled ? local.id : "" + description = "Disambiguated ID restricted to `id_length_limit` characters in total" +} + +output "id_full" { + value = local.enabled ? local.id_full : "" + description = "Disambiguated ID not restricted in length" +} + +output "enabled" { + value = local.enabled + description = "True if module is enabled, false otherwise" +} + +output "namespace" { + value = local.enabled ? local.namespace : "" + description = "Normalized namespace" +} + +output "environment" { + value = local.enabled ? local.environment : "" + description = "Normalized environment" +} + +output "name" { + value = local.enabled ? local.name : "" + description = "Normalized name" +} + +output "stage" { + value = local.enabled ? local.stage : "" + description = "Normalized stage" +} + +output "delimiter" { + value = local.enabled ? local.delimiter : "" + description = "Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes`" +} + +output "attributes" { + value = local.enabled ? local.attributes : [] + description = "List of attributes" +} + +output "tags" { + value = local.enabled ? local.tags : {} + description = "Normalized Tag map" +} + +output "additional_tag_map" { + value = local.additional_tag_map + description = "The merged additional_tag_map" +} + +output "label_order" { + value = local.label_order + description = "The naming order actually used to create the ID" +} + +output "regex_replace_chars" { + value = local.regex_replace_chars + description = "The regex_replace_chars actually used to create the ID" +} + +output "id_length_limit" { + value = local.id_length_limit + description = "The id_length_limit actually used to create the ID, with `0` meaning unlimited" +} + +output "tags_as_list_of_maps" { + value = local.tags_as_list_of_maps + description = "Additional tags as a list of maps, which can be used in several AWS resources" +} + +output "normalized_context" { + value = local.output_context + description = "Normalized context of this module" +} + +output "context" { + value = local.input + description = <<-EOT + Merged but otherwise unmodified input to this module, to be used as context input to other modules. + Note: this version will have null values as defaults, not the values actually used as defaults. +EOT +} + diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/test/Makefile b/.terraform/modules/datadog_integration.forwarder_rds.this/test/Makefile new file mode 100755 index 0000000..ea15d62 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/test/Makefile @@ -0,0 +1,43 @@ +TEST_HARNESS ?= https://github.com/cloudposse/test-harness.git +TEST_HARNESS_BRANCH ?= master +TEST_HARNESS_PATH = $(realpath .test-harness) +BATS_ARGS ?= --tap +BATS_LOG ?= test.log + +# Define a macro to run the tests +define RUN_TESTS +@echo "Running tests in $(1)" +@cd $(1) && bats $(BATS_ARGS) $(addsuffix .bats,$(addprefix $(TEST_HARNESS_PATH)/test/terraform/,$(TESTS))) +endef + +default: all + +-include Makefile.* + +## Provision the test-harnesss +.test-harness: + [ -d $@ ] || git clone --depth=1 -b $(TEST_HARNESS_BRANCH) $(TEST_HARNESS) $@ + +## Initialize the tests +init: .test-harness + +## Install all dependencies (OS specific) +deps:: + @exit 0 + +## Clean up the test harness +clean: + [ "$(TEST_HARNESS_PATH)" == "/" ] || rm -rf $(TEST_HARNESS_PATH) + +## Run all tests +all: module examples/complete + +## Run basic sanity checks against the module itself +module: export TESTS ?= installed lint get-modules module-pinning get-plugins provider-pinning validate terraform-docs input-descriptions output-descriptions +module: deps + $(call RUN_TESTS, ../) + +## Run tests against example +examples/complete: export TESTS ?= installed lint get-modules get-plugins validate init plan apply +examples/complete: deps + $(call RUN_TESTS, ../$@) diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/test/Makefile.alpine b/.terraform/modules/datadog_integration.forwarder_rds.this/test/Makefile.alpine new file mode 100755 index 0000000..7925b18 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/test/Makefile.alpine @@ -0,0 +1,5 @@ +ifneq (,$(wildcard /sbin/apk)) +## Install all dependencies for alpine +deps:: init + @apk add --update terraform-docs@cloudposse json2hcl@cloudposse +endif diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/test/src/Makefile b/.terraform/modules/datadog_integration.forwarder_rds.this/test/src/Makefile new file mode 100755 index 0000000..b772822 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/test/src/Makefile @@ -0,0 +1,30 @@ +export TF_CLI_ARGS_init ?= -get-plugins=true +export TERRAFORM_VERSION ?= $(shell curl -s https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r -M '.current_version' | cut -d. -f1-2) + +.DEFAULT_GOAL : all +.PHONY: all + +## Default target +all: test + +.PHONY : init +## Initialize tests +init: + @exit 0 + +.PHONY : test +## Run tests +test: init + go mod download + go test -v -timeout 60m -run TestExamplesComplete + +## Run tests in docker container +docker/test: + docker run --name terratest --rm -it -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e GITHUB_TOKEN \ + -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" \ + -v $(CURDIR)/../../:/module/ cloudposse/test-harness:latest -C /module/test/src test + +.PHONY : clean +## Clean up files +clean: + rm -rf ../../examples/complete/*.tfstate* diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/test/src/examples_complete_test.go b/.terraform/modules/datadog_integration.forwarder_rds.this/test/src/examples_complete_test.go new file mode 100755 index 0000000..156e293 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/test/src/examples_complete_test.go @@ -0,0 +1,293 @@ +package test + +import ( + "fmt" + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" + "github.com/qdm12/reprint" + "github.com/stretchr/testify/assert" +) + +type NLContext struct { + AdditionalTagMap map[string]string `json:"additional_tag_map"` + Attributes []string `json:"attributes"` + Delimiter interface{} `json:"delimiter"` + Enabled bool `json:"enabled"` + Environment interface{} `json:"environment"` + LabelOrder []string `json:"label_order"` + Name interface{} `json:"name"` + Namespace interface{} `json:"namespace"` + RegexReplaceChars interface{} `json:"regex_replace_chars"` + Stage interface{} `json:"stage"` + Tags map[string]string `json:"tags"` +} + +// Test the Terraform module in examples/complete using Terratest. +func TestExamplesComplete(t *testing.T) { + t.Parallel() + + terraformOptions := &terraform.Options{ + // The path to where our Terraform code is located + TerraformDir: "../../examples/complete", + Upgrade: true, + } + + // At the end of the test, run `terraform destroy` to clean up any resources that were created + defer terraform.Destroy(t, terraformOptions) + + // This will run `terraform init` and `terraform apply` and fail the test if there are any errors + terraform.InitAndApply(t, terraformOptions) + + expectedLabel1Context := NLContext{ + Enabled: true, + Namespace: "CloudPosse", + Environment: "UAT", + Stage: "build", + Name: "Winston Churchroom", + Attributes: []string{"fire", "water", "earth", "air"}, + Delimiter: "-", + LabelOrder: []string{"name", "environment", "stage", "attributes"}, + Tags: map[string]string{ + "City": "Dublin", + "Environment": "Private", + }, + AdditionalTagMap: map[string]string{}, + } + + var expectedLabel1NormalizedContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel1NormalizedContext) + expectedLabel1NormalizedContext.Namespace = "cloudposse" + expectedLabel1NormalizedContext.Environment = "uat" + expectedLabel1NormalizedContext.Name = "winstonchurchroom" + expectedLabel1NormalizedContext.RegexReplaceChars = "/[^-a-zA-Z0-9]/" + expectedLabel1NormalizedContext.Tags = map[string]string{ + "City": "Dublin", + "Environment": "Private", + "Namespace": "cloudposse", + "Stage": "build", + "Name": "winstonchurchroom-uat-build-fire-water-earth-air", + "Attributes": "fire-water-earth-air", + } + + var label1NormalizedContext, label1Context NLContext + // Run `terraform output` to get the value of an output variable + label1 := terraform.OutputMap(t, terraformOptions, "label1") + label1Tags := terraform.OutputMap(t, terraformOptions, "label1_tags") + terraform.OutputStruct(t, terraformOptions, "label1_normalized_context", &label1NormalizedContext) + terraform.OutputStruct(t, terraformOptions, "label1_context", &label1Context) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1["id"]) + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1Tags["Name"]) + assert.Equal(t, "Dublin", label1Tags["City"]) + assert.Equal(t, "Private", label1Tags["Environment"]) + assert.Equal(t, expectedLabel1NormalizedContext, label1NormalizedContext) + assert.Equal(t, expectedLabel1Context, label1Context) + + label1t1 := terraform.OutputMap(t, terraformOptions, "label1t1") + label1t1Tags := terraform.OutputMap(t, terraformOptions, "label1t1_tags") + assert.Equal(t, "winstonchurchroom-uat-6a0b34", label1t1["id"], + "Extra hash character should be added when trailing delimiter is removed") + assert.Equal(t, label1["id"], label1t1["id_full"], "id_full should not be truncated") + assert.Equal(t, label1t1["id"], label1t1Tags["Name"], "Name tag should match ID") + + label1t2 := terraform.OutputMap(t, terraformOptions, "label1t2") + label1t2Tags := terraform.OutputMap(t, terraformOptions, "label1t2_tags") + assert.Equal(t, "winstonchurchroom-uat-b-6a0b3", label1t2["id"]) + assert.Equal(t, label1t2["id"], label1t2Tags["Name"], "Name tag should match ID") + + // Run `terraform output` to get the value of an output variable + label2 := terraform.OutputMap(t, terraformOptions, "label2") + label2Tags := terraform.OutputMap(t, terraformOptions, "label2_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2["id"]) + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2Tags["Name"]) + assert.Equal(t, "London", label2Tags["City"]) + assert.Equal(t, "Public", label2Tags["Environment"]) + + var expectedLabel3cContext, label3cContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel3cContext) + expectedLabel3cContext.Name = "Starfish" + expectedLabel3cContext.Stage = "release" + expectedLabel3cContext.Delimiter = "." + expectedLabel3cContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3cContext.Tags["Eat"] = "Carrot" + expectedLabel3cContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3c := terraform.OutputMap(t, terraformOptions, "label3c") + label3cTags := terraform.OutputMap(t, terraformOptions, "label3c_tags") + terraform.OutputStruct(t, terraformOptions, "label3c_context", &label3cContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3c["id"]) + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3cTags["Name"]) + assert.Equal(t, expectedLabel3cContext, label3cContext) + + var expectedLabel3nContext, label3nContext NLContext + _ = reprint.FromTo(&expectedLabel1NormalizedContext, &expectedLabel3nContext) + expectedLabel3nContext.Name = "Starfish" + expectedLabel3nContext.Stage = "release" + expectedLabel3nContext.Delimiter = "." + expectedLabel3nContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3nContext.Tags["Eat"] = "Carrot" + expectedLabel3nContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3n := terraform.OutputMap(t, terraformOptions, "label3n") + label3nTags := terraform.OutputMap(t, terraformOptions, "label3n_tags") + terraform.OutputStruct(t, terraformOptions, "label3n_context", &label3nContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3n["id"]) + assert.Equal(t, label1Tags["Name"], label3nTags["Name"], + "Tag from label1 normalized context should overwrite label3n generated tag") + assert.Equal(t, expectedLabel3nContext, label3nContext) + + // Run `terraform output` to get the value of an output variable + label4 := terraform.OutputMap(t, terraformOptions, "label4") + label4Tags := terraform.OutputMap(t, terraformOptions, "label4_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4["id"]) + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4Tags["Name"]) + + // Run `terraform output` to get the value of an output variable + label5 := terraform.OutputMap(t, terraformOptions, "label5") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "", label5["id"]) + + label6f := terraform.OutputMap(t, terraformOptions, "label6f") + label6fTags := terraform.OutputMap(t, terraformOptions, "label6f_tags") + // Test of setting var.label_key_case = "lower", var.label_value_case = "upper" + assert.Equal(t, "CP~UW2~PRD~NULL-LABEL", label6f["id_full"]) + assert.Equal(t, label6f["id_full"], label6f["id"], "id should not be truncated") + assert.Equal(t, label6f["id"], label6fTags["name"], "Name tag should match ID") + + label6t := terraform.OutputMap(t, terraformOptions, "label6t") + label6tTags := terraform.OutputMap(t, terraformOptions, "label6t_tags") + assert.Equal(t, "CPUW2PRDNULL-LABEL", label6t["id_full"]) + assert.NotEqual(t, label6t["id_full"], label6t["id"], "id should be truncated") + assert.Equal(t, label6t["id"], label6tTags["name"], "Name tag should match ID") + assert.Equal(t, label6t["id_length_limit"], fmt.Sprintf("%d", len(label6t["id"])), + "Truncated ID length should equal length limit") + + label7 := terraform.OutputMap(t, terraformOptions, "label7") + assert.Equal(t, "eg-demo-blue-cluster-nodegroup", label7["id"], "var.attributes should be appended after context.attributes") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter=""` returns expected value of id, context id + label8dndID := terraform.Output(t, terraformOptions, "label8dnd_id") + label8dndContextID := terraform.Output(t, terraformOptions, "label8dnd_context_id") + assert.Equal(t, "egdemobluecluster", label8dndID) + assert.Equal(t, label8dndID, label8dndContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter="x"` returns expected value of id, context id + label8dcdID := terraform.Output(t, terraformOptions, "label8dcd_id") + label8dcdContextID := terraform.Output(t, terraformOptions, "label8dcd_context_id") + assert.Equal(t, "egxdemoxbluexcluster", label8dcdID) + assert.Equal(t, label8dcdID, label8dcdContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=lower` returns expected values of id, tags, context tags + label8dExpectedTags := map[string]string{ + "Attributes": "cluster", + "Environment": "demo", + "Name": "eg-demo-blue-cluster", + "Namespace": "eg", + "kubernetes.io/cluster/": "shared", + } + + label8dID := terraform.Output(t, terraformOptions, "label8d_id") + label8dContextID := terraform.Output(t, terraformOptions, "label8d_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8dID) + assert.Equal(t, label8dID, label8dContextID, "ID and context ID should be equal") + + label8dTags := terraform.OutputMap(t, terraformOptions, "label8d_tags") + label8dContextTags := terraform.OutputMap(t, terraformOptions, "label8d_context_tags") + + assert.Exactly(t, label8dExpectedTags, label8dTags, "generated tags are different from expected") + assert.Exactly(t, label8dTags, label8dContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=lower` and `label_value_case=lower` returns expected values of id, tags, context tags + label8lExpectedTags := map[string]string{ + "attributes": "cluster", + "environment": "demo", + "name": "eg-demo-blue-cluster", + "namespace": "eg", + "kubernetes.io/cluster/": "shared", + "upperTEST": "testUPPER", + } + + label8lID := terraform.Output(t, terraformOptions, "label8l_id") + label8lContextID := terraform.Output(t, terraformOptions, "label8l_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8lID) + assert.Equal(t, label8lID, label8lContextID, "ID and context ID should be equal") + + label8lTags := terraform.OutputMap(t, terraformOptions, "label8l_tags") + label8lContextTags := terraform.OutputMap(t, terraformOptions, "label8l_context_tags") + + assert.Exactly(t, label8lExpectedTags, label8lTags, "generated tags are different from expected") + assert.Exactly(t, label8lTags, label8lContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=title` returns expected values of id, tags, context tags + label8tExpectedTags := map[string]string{ + "Attributes": "Eks-Cluster", + "Environment": "Demo", + "Name": "Eg-Demo-Blue-Eks-Cluster", + "Namespace": "Eg", + "kubernetes.io/cluster/": "shared", + } + + label8tID := terraform.Output(t, terraformOptions, "label8t_id") + label8tContextID := terraform.Output(t, terraformOptions, "label8t_context_id") + assert.Equal(t, "Eg-Demo-Blue-Eks-Cluster", label8tID) + assert.Equal(t, label8tID, label8tContextID, "ID and context ID should be equal") + + label8tTags := terraform.OutputMap(t, terraformOptions, "label8t_tags") + label8tContextTags := terraform.OutputMap(t, terraformOptions, "label8t_context_tags") + + assert.Exactly(t, label8tExpectedTags, label8tTags, "generated tags are different from expected") + assert.Exactly(t, label8tTags, label8tContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=upper` and `label_value_case=upper` returns expected values of id, tags, context tags + label8uExpectedTags := map[string]string{ + "ATTRIBUTES": "CLUSTER", + "ENVIRONMENT": "DEMO", + "NAME": "EG-DEMO-BLUE-CLUSTER", + "NAMESPACE": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8uID := terraform.Output(t, terraformOptions, "label8u_id") + label8uContextID := terraform.Output(t, terraformOptions, "label8u_context_id") + assert.Equal(t, "EG-DEMO-BLUE-CLUSTER", label8uID) + assert.Equal(t, label8uID, label8uContextID, "ID and context ID should be equal") + + label8uTags := terraform.OutputMap(t, terraformOptions, "label8u_tags") + label8uContextTags := terraform.OutputMap(t, terraformOptions, "label8u_context_tags") + + assert.Exactly(t, label8uExpectedTags, label8uTags, "generated tags are different from expected") + assert.Exactly(t, label8uTags, label8uContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=none` returns expected values of id, tags, context tags + label8nExpectedTags := map[string]string{ + "Attributes": "eks-ClusteR", + "Environment": "demo", + "Name": "EG-demo-blue-eks-ClusteR", + "Namespace": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8nID := terraform.Output(t, terraformOptions, "label8n_id") + label8nContextID := terraform.Output(t, terraformOptions, "label8n_context_id") + assert.Equal(t, "EG-demo-blue-eks-ClusteR", label8nID) + assert.Equal(t, label8nID, label8nContextID, "ID and context ID should be equal") + + label8nTags := terraform.OutputMap(t, terraformOptions, "label8n_tags") + label8nContextTags := terraform.OutputMap(t, terraformOptions, "label8n_context_tags") + + assert.Exactly(t, label8nExpectedTags, label8nTags, "generated tags are different from expected") + assert.Exactly(t, label8nTags, label8nContextTags, "tags and context tags should be equal") +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/test/src/go.mod b/.terraform/modules/datadog_integration.forwarder_rds.this/test/src/go.mod new file mode 100755 index 0000000..d866541 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/test/src/go.mod @@ -0,0 +1,9 @@ +module github.com/cloudposse/terraform-null-label + +go 1.14 + +require ( + github.com/gruntwork-io/terratest v0.31.1 + github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 + github.com/stretchr/testify v1.6.1 +) diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/test/src/go.sum b/.terraform/modules/datadog_integration.forwarder_rds.this/test/src/go.sum new file mode 100755 index 0000000..b8d46b1 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/test/src/go.sum @@ -0,0 +1,595 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= +github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.5/go.mod h1:foo3aIXRQ90zFve3r0QiDsrjGDUwWhKl0ZOQy1CT14k= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= +github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200109221225-a4f60165b7a3/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= +github.com/gruntwork-io/terratest v0.31.1 h1:MPGe/5pGgJAIZ/hb+0LM1KyJKSi/QyxSkHoP9/CBhJg= +github.com/gruntwork-io/terratest v0.31.1/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= +github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4= +github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= +github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= +k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= +k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= +k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= +k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= +k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= +k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= +k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= +modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/variables.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/variables.tf new file mode 100755 index 0000000..40fb268 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/variables.tf @@ -0,0 +1,157 @@ +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds.this/versions.tf b/.terraform/modules/datadog_integration.forwarder_rds.this/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds.this/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/LICENSE b/.terraform/modules/datadog_integration.forwarder_rds_label/LICENSE new file mode 100755 index 0000000..c844c70 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017-2020 Cloud Posse, LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/Makefile b/.terraform/modules/datadog_integration.forwarder_rds_label/Makefile new file mode 100755 index 0000000..97d8087 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/Makefile @@ -0,0 +1,10 @@ +SHELL := /bin/bash + +# List of targets the `readme` target should call before generating the readme +export README_DEPS ?= docs/targets.md docs/terraform.md + +-include $(shell curl -sSL -o .build-harness "https://git.io/build-harness"; echo .build-harness) + +## Lint terraform code +lint: + $(SELF) terraform/install terraform/get-modules terraform/get-plugins terraform/lint terraform/validate diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/README.md b/.terraform/modules/datadog_integration.forwarder_rds_label/README.md new file mode 100755 index 0000000..32950e4 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/README.md @@ -0,0 +1,938 @@ + +# terraform-null-label [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-null-label.svg)](https://github.com/cloudposse/terraform-null-label/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) + + +[![README Header][readme_header_img]][readme_header_link] + +[![Cloud Posse][logo]](https://cpco.io/homepage) + + + +Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + +This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. +However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). +So if you prefer the term `stage` to `environment` +you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. +- If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. +- If you want the attributes in a different order, you can specify that, too, with the `label_order` list. +- You can set a maximum length for the name, and the module will create a unique name that fits within that length. +- You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. +- The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + +It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. +For example, if you have 10 instances, there should be 10 different labels. +However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + +All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + +**NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. +With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + +- Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. +- Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. +- Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. + + +--- + +This project is part of our comprehensive ["SweetOps"](https://cpco.io/sweetops) approach towards DevOps. +[][share_email] +[][share_googleplus] +[][share_facebook] +[][share_reddit] +[][share_linkedin] +[][share_twitter] + + +[![Terraform Open Source Modules](https://docs.cloudposse.com/images/terraform-open-source-modules.svg)][terraform_modules] + + + +It's 100% Open Source and licensed under the [APACHE2](LICENSE). + + + + + + + +We literally have [*hundreds of terraform modules*][terraform_modules] that are Open Source and well-maintained. Check them out! + + + + + + + +## Security & Compliance [](https://bridgecrew.io/) + +Security scanning is graciously provided by Bridgecrew. Bridgecrew is the leading fully hosted, cloud-native solution providing continuous Terraform security and compliance. + +| Benchmark | Description | +|--------|---------------| +| [![Infrastructure Security](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/general)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=INFRASTRUCTURE+SECURITY) | Infrastructure Security Compliance | +| [![CIS KUBERNETES](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_kubernetes)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+KUBERNETES+V1.5) | Center for Internet Security, KUBERNETES Compliance | +| [![CIS AWS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_aws)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AWS+V1.2) | Center for Internet Security, AWS Compliance | +| [![CIS AZURE](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_azure)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AZURE+V1.1) | Center for Internet Security, AZURE Compliance | +| [![PCI-DSS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/pci)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=PCI-DSS+V3.2) | Payment Card Industry Data Security Standards Compliance | +| [![NIST-800-53](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/nist)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=NIST-800-53) | National Institute of Standards and Technology Compliance | +| [![ISO27001](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/iso)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=ISO27001) | Information Security Management System, ISO/IEC 27001 Compliance | +| [![SOC2](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/soc2)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=SOC2)| Service Organization Control 2 Compliance | +| [![CIS GCP](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_gcp)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+GCP+V1.1) | Center for Internet Security, GCP Compliance | +| [![HIPAA](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/hipaa)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=HIPAA) | Health Insurance Portability and Accountability Compliance | + + + +## Usage + + +**IMPORTANT:** We do not pin modules to versions in our examples because of the +difficulty of keeping the versions in the documentation in sync with the latest released versions. +We highly recommend that in your code you pin the version to the exact version you are +using so that your infrastructure remains stable, and update versions in a +systematic way so that they do not catch you by surprise. + +Also, because of a bug in the Terraform registry ([hashicorp/terraform#21417](https://github.com/hashicorp/terraform/issues/21417)), +the registry shows many of our inputs as required when in fact they are optional. +The table below correctly indicates which inputs are required. + + +### Defaults + +Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. +The context object is a single object that contains all the input values for `terraform-null-label`. +However, each input value can also be specified individually by name as a standard Terraform variable, +and the value of those variables, when set to something other than `null`, will override the value +in the context object. In order to allow chaining of these objects, where the context object input to one +module is transformed and passed to the next module, all the variables default to `null` or empty collections. +The actual default values used when nothing is explicitly set are describe in the documentation below. + +For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, +`terraform-null-label` will actually use the default delimiter `-` (hyphen). + +A non-obvious but intentional consequence of this design is that once a module sets a non-default value, +future modules in the chain cannot reset the value back to the original default. Insted, the new setting +becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, +so once a tag is added, it will remain in the tag set and cannot be removed, although its value can +be overwritten. + +### Simple Example + +```hcl +module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} +``` + +This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` +(you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + +Now reference the label when creating an instance: + +```hcl +resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags +} +``` + +Or define a security group: + +```hcl +resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} +``` + + +### Advanced Example + +Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + +```hcl +module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] +} + +module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] +} +``` + +
+ +### Advanced Example 2 + +Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + +```hcl +tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } +] +``` + +Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + +```hcl +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} +``` + +
+ +### Advanced Example 3 + +See [complete example](./examples/complete) for even more examples. + +This example shows how you can pass the `context` output of one label module to the next label_module, +allowing you to create one label that has the base set of values, and then creating every extra label +as a derivative of that. + +
Click to show + +```hcl +module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} +``` + +This creates label outputs like this: + +```hcl +label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" +} +label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } +} +label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } +} +label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" +} +label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" +} +label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } +} +label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" +} +label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, +] +label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" +} +label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } +} +label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } +} +label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" +} + +``` + +
+ + + + + + + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + + + + +## Share the Love + +Like this project? Please give it a ★ on [our GitHub](https://github.com/cloudposse/terraform-null-label)! (it helps us **a lot**) + +Are you using this project or any of our other projects? Consider [leaving a testimonial][testimonial]. =) + + +## Related Projects + +Check out these related projects. + +- [terraform-terraform-label](https://github.com/cloudposse/terraform-terraform-label) - Terraform Module to define a consistent naming convention by (namespace, environment, stage, name, [attributes]) + + + +## Help + +**Got a question?** We got answers. + +File a GitHub [issue](https://github.com/cloudposse/terraform-null-label/issues), send us an [email][email] or join our [Slack Community][slack]. + +[![README Commercial Support][readme_commercial_support_img]][readme_commercial_support_link] + +## DevOps Accelerator for Startups + + +We are a [**DevOps Accelerator**][commercial_support]. We'll help you build your cloud infrastructure from the ground up so you can own it. Then we'll show you how to operate it and stick around for as long as you need us. + +[![Learn More](https://img.shields.io/badge/learn%20more-success.svg?style=for-the-badge)][commercial_support] + +Work directly with our team of DevOps experts via email, slack, and video conferencing. + +We deliver 10x the value for a fraction of the cost of a full-time engineer. Our track record is not even funny. If you want things done right and you need it done FAST, then we're your best bet. + +- **Reference Architecture.** You'll get everything you need from the ground up built using 100% infrastructure as code. +- **Release Engineering.** You'll have end-to-end CI/CD with unlimited staging environments. +- **Site Reliability Engineering.** You'll have total visibility into your apps and microservices. +- **Security Baseline.** You'll have built-in governance with accountability and audit logs for all changes. +- **GitOps.** You'll be able to operate your infrastructure via Pull Requests. +- **Training.** You'll receive hands-on training so your team can operate what we build. +- **Questions.** You'll have a direct line of communication between our teams via a Shared Slack channel. +- **Troubleshooting.** You'll get help to triage when things aren't working. +- **Code Reviews.** You'll receive constructive feedback on Pull Requests. +- **Bug Fixes.** We'll rapidly work with you to fix any bugs in our projects. + +## Slack Community + +Join our [Open Source Community][slack] on Slack. It's **FREE** for everyone! Our "SweetOps" community is where you get to talk with others who share a similar vision for how to rollout and manage infrastructure. This is the best place to talk shop, ask questions, solicit feedback, and work together as a community to build totally *sweet* infrastructure. + +## Discourse Forums + +Participate in our [Discourse Forums][discourse]. Here you'll find answers to commonly asked questions. Most questions will be related to the enormous number of projects we support on our GitHub. Come here to collaborate on answers, find solutions, and get ideas about the products and services we value. It only takes a minute to get started! Just sign in with SSO using your GitHub account. + +## Newsletter + +Sign up for [our newsletter][newsletter] that covers everything on our technology radar. Receive updates on what we're up to on GitHub as well as awesome new projects we discover. + +## Office Hours + +[Join us every Wednesday via Zoom][office_hours] for our weekly "Lunch & Learn" sessions. It's **FREE** for everyone! + +[![zoom](https://img.cloudposse.com/fit-in/200x200/https://cloudposse.com/wp-content/uploads/2019/08/Powered-by-Zoom.png")][office_hours] + +## Contributing + +### Bug Reports & Feature Requests + +Please use the [issue tracker](https://github.com/cloudposse/terraform-null-label/issues) to report any bugs or file feature requests. + +### Developing + +If you are interested in being a contributor and want to get involved in developing this project or [help out](https://cpco.io/help-out) with our other projects, we would love to hear from you! Shoot us an [email][email]. + +In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. + + 1. **Fork** the repo on GitHub + 2. **Clone** the project to your own machine + 3. **Commit** changes to your own branch + 4. **Push** your work back up to your fork + 5. Submit a **Pull Request** so that we can review your changes + +**NOTE:** Be sure to merge the latest changes from "upstream" before making a pull request! + + +## Copyright + +Copyright © 2017-2021 [Cloud Posse, LLC](https://cpco.io/copyright) + + + +## License + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +See [LICENSE](LICENSE) for full details. + +```text +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +``` + + + + + + + + + +## Trademarks + +All other trademarks referenced herein are the property of their respective owners. + +## About + +This project is maintained and funded by [Cloud Posse, LLC][website]. Like it? Please let us know by [leaving a testimonial][testimonial]! + +[![Cloud Posse][logo]][website] + +We're a [DevOps Professional Services][hire] company based in Los Angeles, CA. We ❤️ [Open Source Software][we_love_open_source]. + +We offer [paid support][commercial_support] on all of our projects. + +Check out [our other projects][github], [follow us on twitter][twitter], [apply for a job][jobs], or [hire us][hire] to help with your cloud strategy and implementation. + + + +### Contributors + + +| [![Erik Osterman][osterman_avatar]][osterman_homepage]
[Erik Osterman][osterman_homepage] | [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]
[Andriy Knysh][aknysh_homepage] | [![Igor Rodionov][goruha_avatar]][goruha_homepage]
[Igor Rodionov][goruha_homepage] | [![Sergey Vasilyev][s2504s_avatar]][s2504s_homepage]
[Sergey Vasilyev][s2504s_homepage] | [![Michael Pereira][MichaelPereira_avatar]][MichaelPereira_homepage]
[Michael Pereira][MichaelPereira_homepage] | [![Jamie Nelson][Jamie-BitFlight_avatar]][Jamie-BitFlight_homepage]
[Jamie Nelson][Jamie-BitFlight_homepage] | [![Vladimir][SweetOps_avatar]][SweetOps_homepage]
[Vladimir][SweetOps_homepage] | [![Daren Desjardins][darend_avatar]][darend_homepage]
[Daren Desjardins][darend_homepage] | [![Maarten van der Hoef][maartenvanderhoef_avatar]][maartenvanderhoef_homepage]
[Maarten van der Hoef][maartenvanderhoef_homepage] | [![Adam Tibbing][tibbing_avatar]][tibbing_homepage]
[Adam Tibbing][tibbing_homepage] | +|---|---|---|---|---|---|---|---|---|---| + + + [osterman_homepage]: https://github.com/osterman + [osterman_avatar]: https://img.cloudposse.com/150x150/https://github.com/osterman.png + [aknysh_homepage]: https://github.com/aknysh + [aknysh_avatar]: https://img.cloudposse.com/150x150/https://github.com/aknysh.png + [goruha_homepage]: https://github.com/goruha + [goruha_avatar]: https://img.cloudposse.com/150x150/https://github.com/goruha.png + [s2504s_homepage]: https://github.com/s2504s + [s2504s_avatar]: https://img.cloudposse.com/150x150/https://github.com/s2504s.png + [MichaelPereira_homepage]: https://github.com/MichaelPereira + [MichaelPereira_avatar]: https://img.cloudposse.com/150x150/https://github.com/MichaelPereira.png + [Jamie-BitFlight_homepage]: https://github.com/Jamie-BitFlight + [Jamie-BitFlight_avatar]: https://img.cloudposse.com/150x150/https://github.com/Jamie-BitFlight.png + [SweetOps_homepage]: https://github.com/SweetOps + [SweetOps_avatar]: https://img.cloudposse.com/150x150/https://github.com/SweetOps.png + [darend_homepage]: https://github.com/darend + [darend_avatar]: https://img.cloudposse.com/150x150/https://github.com/darend.png + [maartenvanderhoef_homepage]: https://github.com/maartenvanderhoef + [maartenvanderhoef_avatar]: https://img.cloudposse.com/150x150/https://github.com/maartenvanderhoef.png + [tibbing_homepage]: https://github.com/tibbing + [tibbing_avatar]: https://img.cloudposse.com/150x150/https://github.com/tibbing.png + +[![README Footer][readme_footer_img]][readme_footer_link] +[![Beacon][beacon]][website] + + [logo]: https://cloudposse.com/logo-300x69.svg + [docs]: https://cpco.io/docs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=docs + [website]: https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=website + [github]: https://cpco.io/github?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=github + [jobs]: https://cpco.io/jobs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=jobs + [hire]: https://cpco.io/hire?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=hire + [slack]: https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=slack + [linkedin]: https://cpco.io/linkedin?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=linkedin + [twitter]: https://cpco.io/twitter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=twitter + [testimonial]: https://cpco.io/leave-testimonial?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=testimonial + [office_hours]: https://cloudposse.com/office-hours?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=office_hours + [newsletter]: https://cpco.io/newsletter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=newsletter + [discourse]: https://ask.sweetops.com/?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=discourse + [email]: https://cpco.io/email?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=email + [commercial_support]: https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=commercial_support + [we_love_open_source]: https://cpco.io/we-love-open-source?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=we_love_open_source + [terraform_modules]: https://cpco.io/terraform-modules?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=terraform_modules + [readme_header_img]: https://cloudposse.com/readme/header/img + [readme_header_link]: https://cloudposse.com/readme/header/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_header_link + [readme_footer_img]: https://cloudposse.com/readme/footer/img + [readme_footer_link]: https://cloudposse.com/readme/footer/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_footer_link + [readme_commercial_support_img]: https://cloudposse.com/readme/commercial-support/img + [readme_commercial_support_link]: https://cloudposse.com/readme/commercial-support/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_commercial_support_link + [share_twitter]: https://twitter.com/intent/tweet/?text=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_linkedin]: https://www.linkedin.com/shareArticle?mini=true&title=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_reddit]: https://reddit.com/submit/?url=https://github.com/cloudposse/terraform-null-label + [share_facebook]: https://facebook.com/sharer/sharer.php?u=https://github.com/cloudposse/terraform-null-label + [share_googleplus]: https://plus.google.com/share?url=https://github.com/cloudposse/terraform-null-label + [share_email]: mailto:?subject=terraform-null-label&body=https://github.com/cloudposse/terraform-null-label + [beacon]: https://ga-beacon.cloudposse.com/UA-76589703-4/cloudposse/terraform-null-label?pixel&cs=github&cm=readme&an=terraform-null-label diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/README.yaml b/.terraform/modules/datadog_integration.forwarder_rds_label/README.yaml new file mode 100755 index 0000000..42bdb84 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/README.yaml @@ -0,0 +1,618 @@ +name: terraform-null-label +tags: +- aws +- terraform +- terraform-modules +- naming-convention +- name +- namespace +- stage +categories: +- terraform-modules/supported +license: APACHE2 +github_repo: cloudposse/terraform-null-label +badges: +- name: Latest Release + image: https://img.shields.io/github/release/cloudposse/terraform-null-label.svg + url: https://github.com/cloudposse/terraform-null-label/releases/latest +- name: Slack Community + image: https://slack.cloudposse.com/badge.svg + url: https://slack.cloudposse.com +related: +- name: terraform-terraform-label + description: Terraform Module to define a consistent naming convention by (namespace, + environment, stage, name, [attributes]) + url: https://github.com/cloudposse/terraform-terraform-label +description: |- + Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + + This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. + However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). + So if you prefer the term `stage` to `environment` + you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. + - If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. + - If you want the attributes in a different order, you can specify that, too, with the `label_order` list. + - You can set a maximum length for the name, and the module will create a unique name that fits within that length. + - You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. + - The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + + It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. + For example, if you have 10 instances, there should be 10 different labels. + However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + + All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + + **NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. + With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + + - Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. + - Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. + - Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. +usage: |- + ### Defaults + + Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. + The context object is a single object that contains all the input values for `terraform-null-label`. + However, each input value can also be specified individually by name as a standard Terraform variable, + and the value of those variables, when set to something other than `null`, will override the value + in the context object. In order to allow chaining of these objects, where the context object input to one + module is transformed and passed to the next module, all the variables default to `null` or empty collections. + The actual default values used when nothing is explicitly set are describe in the documentation below. + + For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, + `terraform-null-label` will actually use the default delimiter `-` (hyphen). + + A non-obvious but intentional consequence of this design is that once a module sets a non-default value, + future modules in the chain cannot reset the value back to the original default. Insted, the new setting + becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, + so once a tag is added, it will remain in the tag set and cannot be removed, although its value can + be overwritten. + + ### Simple Example + + ```hcl + module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + ``` + + This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` + (you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + + Now reference the label when creating an instance: + + ```hcl + resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags + } + ``` + + Or define a security group: + + ```hcl + resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + } + ``` + + + ### Advanced Example + + Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + + ```hcl + module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] + } + + module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] + } + ``` + +
+ + ### Advanced Example 2 + + Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + + ```hcl + tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } + ] + ``` + + Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + + ```hcl + ################################ + # terraform-null-label example # + ################################ + module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } + } + + ####################### + # Launch template # + ####################### + resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } + } + + ###################### + # Autoscaling group # + ###################### + resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps + } + ``` + +
+ + ### Advanced Example 3 + + See [complete example](./examples/complete) for even more examples. + + This example shows how you can pass the `context` output of one label module to the next label_module, + allowing you to create one label that has the base set of values, and then creating every extra label + as a derivative of that. + +
Click to show + + ```hcl + module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } + } + + module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } + } + + module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } + } + ``` + + This creates label outputs like this: + + ```hcl + label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" + } + label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } + } + label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + } + label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" + } + label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } + } + label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" + } + label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, + ] + label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" + } + label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } + } + label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + } + label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + + ``` + +
+ +include: +- docs/targets.md +- docs/terraform.md +contributors: +- name: Erik Osterman + github: osterman +- name: Andriy Knysh + github: aknysh +- name: Igor Rodionov + github: goruha +- name: Sergey Vasilyev + github: s2504s +- name: Michael Pereira + github: MichaelPereira +- name: Jamie Nelson + github: Jamie-BitFlight +- name: Vladimir + github: SweetOps +- name: Daren Desjardins + github: darend +- name: Maarten van der Hoef + github: maartenvanderhoef +- name: Adam Tibbing + github: tibbing diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/docs/targets.md b/.terraform/modules/datadog_integration.forwarder_rds_label/docs/targets.md new file mode 100755 index 0000000..3dce8b3 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/docs/targets.md @@ -0,0 +1,12 @@ + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/docs/terraform.md b/.terraform/modules/datadog_integration.forwarder_rds_label/docs/terraform.md new file mode 100755 index 0000000..d4f48f4 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/docs/terraform.md @@ -0,0 +1,54 @@ + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars new file mode 100755 index 0000000..f7c725f --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars @@ -0,0 +1,12 @@ +namespace = "eg" +stage = "prod" +name = "app" + +tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" +} + +additional_tag_map = { + propagate_at_launch = "true" +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/autoscalinggroup/context.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/autoscalinggroup/context.tf new file mode 100755 index 0000000..b97f05f --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/autoscalinggroup/context.tf @@ -0,0 +1,216 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/autoscalinggroup/main.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/autoscalinggroup/main.tf new file mode 100755 index 0000000..f0d3aa6 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/autoscalinggroup/main.tf @@ -0,0 +1,104 @@ +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + + context = module.this.context +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template { + id = aws_launch_template.default.id + version = "$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} + +################################ +# Provider # +################################ +provider "aws" { + region = "eu-west-1" + + # Make it faster by skipping unneeded checks here + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +############################################################## +# Data sources to get VPC, subnets and security group details +############################################################## +data "aws_vpc" "default" { + default = true +} + +data "aws_subnet_ids" "all" { + vpc_id = data.aws_vpc.default.id +} + +data "aws_security_group" "default" { + vpc_id = data.aws_vpc.default.id + name = "default" +} + +data "aws_ami" "amazon_linux" { + most_recent = true + + owners = ["amazon"] + + filter { + name = "name" + + values = [ + "amzn-ami-hvm-*-x86_64-gp2", + ] + } + + filter { + name = "owner-alias" + + values = [ + "amazon", + ] + } +} + diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/autoscalinggroup/outputs.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/autoscalinggroup/outputs.tf new file mode 100755 index 0000000..f8fcce5 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/autoscalinggroup/outputs.tf @@ -0,0 +1,12 @@ +# terraform-null-label example used here: Output list of tags applied in each format +output "tags_as_list_of_maps" { + value = module.label.tags_as_list_of_maps +} + +output "tags" { + value = module.label.tags +} + +output "id" { + value = module.label.id +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/autoscalinggroup/versions.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/autoscalinggroup/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/autoscalinggroup/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/complete.auto.tfvars b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/complete.auto.tfvars new file mode 100755 index 0000000..e7bc519 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/complete.auto.tfvars @@ -0,0 +1,10 @@ +namespace = "cp" +environment = "uw2" +stage = "prd" +name = "null-label" + +delimiter = "" +id_length_limit = 6 + +label_key_case = "lower" +label_value_case = "upper" diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/context.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/context.tf new file mode 100755 index 0000000..973d4dc --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/context.tf @@ -0,0 +1,217 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label1.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label1.tf new file mode 100755 index 0000000..8da353b --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label1.tf @@ -0,0 +1,42 @@ +module "label1" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label1" { + value = { + id = module.label1.id + name = module.label1.name + namespace = module.label1.namespace + stage = module.label1.stage + attributes = module.label1.attributes + delimiter = module.label1.delimiter + } +} + +output "label1_tags" { + value = module.label1.tags +} + +output "label1_context" { + value = module.label1.context +} + +output "label1_normalized_context" { + value = module.label1.normalized_context +} + + + diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label1t1.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label1t1.tf new file mode 100755 index 0000000..2bcb362 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label1t1.tf @@ -0,0 +1,18 @@ +module "label1t1" { + source = "../../" + + id_length_limit = 28 + + context = module.label1.context +} + +output "label1t1" { + value = { + id = module.label1t1.id + id_full = module.label1t1.id_full + } +} + +output "label1t1_tags" { + value = module.label1t1.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label1t2.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label1t2.tf new file mode 100755 index 0000000..5df651e --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label1t2.tf @@ -0,0 +1,18 @@ +module "label1t2" { + source = "../../" + + id_length_limit = 29 + + context = module.label1.context +} + +output "label1t2" { + value = { + id = module.label1t2.id + id_full = module.label1t2.id_full + } +} + +output "label1t2_tags" { + value = module.label1t2.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label2.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label2.tf new file mode 100755 index 0000000..faf7450 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label2.tf @@ -0,0 +1,42 @@ +module "label2" { + source = "../../" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + regex_replace_chars = "/[^a-zA-Z0-9-+]/" + + additional_tag_map = { + propagate_at_launch = "true" + additional_tag = "yes" + } + + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +output "label2" { + value = { + id = module.label2.id + name = module.label2.name + namespace = module.label2.namespace + stage = module.label2.stage + attributes = module.label2.attributes + delimiter = module.label2.delimiter + } +} + +output "label2_tags" { + value = module.label2.tags +} + +output "label2_tags_as_list_of_maps" { + value = module.label2.tags_as_list_of_maps +} + +output "label2_context" { + value = module.label2.context +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label3c.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label3c.tf new file mode 100755 index 0000000..338a636 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label3c.tf @@ -0,0 +1,36 @@ +module "label3c" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3c" { + value = { + id = module.label3c.id + name = module.label3c.name + namespace = module.label3c.namespace + stage = module.label3c.stage + attributes = module.label3c.attributes + delimiter = module.label3c.delimiter + } +} + +output "label3c_tags" { + value = module.label3c.tags +} + +output "label3c_context" { + value = module.label3c.context +} + +output "label3c_normalized_context" { + value = module.label3c.normalized_context +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label3n.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label3n.tf new file mode 100755 index 0000000..ca51282 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label3n.tf @@ -0,0 +1,36 @@ +module "label3n" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.normalized_context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3n" { + value = { + id = module.label3n.id + name = module.label3n.name + namespace = module.label3n.namespace + stage = module.label3n.stage + attributes = module.label3n.attributes + delimiter = module.label3n.delimiter + } +} + +output "label3n_tags" { + value = module.label3n.tags +} + +output "label3n_context" { + value = module.label3n.context +} + +output "label3n_normalized_context" { + value = module.label3n.normalized_context +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label4.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label4.tf new file mode 100755 index 0000000..74e3ca1 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label4.tf @@ -0,0 +1,34 @@ +module "label4" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + name = "Example Cluster" + attributes = ["big", "fat", "honking", "cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label4" { + value = { + id = module.label4.id + name = module.label4.name + namespace = module.label4.namespace + stage = module.label4.stage + attributes = module.label4.attributes + delimiter = module.label4.delimiter + } +} + +output "label4_tags" { + value = module.label4.tags +} + +output "label4_context" { + value = module.label4.context +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label5.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label5.tf new file mode 100755 index 0000000..0f0a76e --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label5.tf @@ -0,0 +1,33 @@ +module "label5" { + source = "../../" + enabled = false + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + } +} + +output "label5" { + value = { + id = module.label5.id + name = module.label5.name + namespace = module.label5.namespace + stage = module.label5.stage + attributes = module.label5.attributes + delimiter = module.label5.delimiter + } +} + +output "label5_tags" { + value = module.label5.tags +} + +output "label5_context" { + value = module.label5.context +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label6f.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label6f.tf new file mode 100755 index 0000000..1ce1bab --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label6f.tf @@ -0,0 +1,20 @@ +module "label6f" { + source = "../../" + + delimiter = "~" + id_length_limit = 0 + + # Use values from tfvars + context = module.this.context +} + +output "label6f" { + value = { + id = module.label6f.id + id_full = module.label6f.id_full + } +} + +output "label6f_tags" { + value = module.label6f.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label6t.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label6t.tf new file mode 100755 index 0000000..b5d9bc1 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label6t.tf @@ -0,0 +1,19 @@ +module "label6t" { + source = "../../" + + # Use values from tfvars, + # specifically: complete.auto.tfvars + context = module.this.context +} + +output "label6t" { + value = { + id = module.label6t.id + id_full = module.label6t.id_full + id_length_limit = module.this.context.id_length_limit + } +} + +output "label6t_tags" { + value = module.label6t.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label7.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label7.tf new file mode 100755 index 0000000..bb365d4 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label7.tf @@ -0,0 +1,44 @@ +module "label7a" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + } +} + +module "label7" { + source = "../../" + + attributes = ["nodegroup"] + + context = module.label7a.context +} + + +output "label7" { + value = { + id = module.label7.id + name = module.label7.name + namespace = module.label7.namespace + stage = module.label7.stage + attributes = module.label7.attributes + delimiter = module.label7.delimiter + } +} + +output "label7_id" { + value = module.label7.id +} + +output "label7_attributes" { + value = module.label7.attributes +} + +output "label7_context" { + value = module.label7.context +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label8d.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label8d.tf new file mode 100755 index 0000000..4252419 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label8d.tf @@ -0,0 +1,44 @@ +module "label8d" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8d_context" { + source = "../../" + + context = module.label8d.context +} + +output "label8d_context_id" { + value = module.label8d_context.id +} + +output "label8d_context_context" { + value = module.label8d_context.context +} + +output "label8d_context_tags" { + value = module.label8d_context.tags +} + +output "label8d_id" { + value = module.label8d.id +} + +output "label8d_context" { + value = module.label8d.context +} + +output "label8d_tags" { + value = module.label8d.tags +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label8dcd.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label8dcd.tf new file mode 100755 index 0000000..ccdae21 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label8dcd.tf @@ -0,0 +1,24 @@ +module "label8dcd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "x" +} + +module "label8dcd_context" { + source = "../../" + + context = module.label8dcd.context +} + +output "label8dcd_context_id" { + value = module.label8dcd_context.id +} + +output "label8dcd_id" { + value = module.label8dcd.id +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label8dnd.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label8dnd.tf new file mode 100755 index 0000000..2edb378 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label8dnd.tf @@ -0,0 +1,24 @@ +module "label8dnd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "" +} + +module "label8dnd_context" { + source = "../../" + + context = module.label8dnd.context +} + +output "label8dnd_context_id" { + value = module.label8dnd_context.id +} + +output "label8dnd_id" { + value = module.label8dnd.id +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label8l.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label8l.tf new file mode 100755 index 0000000..7462f9e --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label8l.tf @@ -0,0 +1,46 @@ +module "label8l" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "lower" + label_value_case = "lower" + + tags = { + "kubernetes.io/cluster/" = "shared" + "upperTEST" = "testUPPER" + } +} + +module "label8l_context" { + source = "../../" + + context = module.label8l.context +} + +output "label8l_context_id" { + value = module.label8l_context.id +} + +output "label8l_context_context" { + value = module.label8l_context.context +} + +output "label8l_context_tags" { + value = module.label8l_context.tags +} + +output "label8l_id" { + value = module.label8l.id +} + +output "label8l_context" { + value = module.label8l.context +} + +output "label8l_tags" { + value = module.label8l.tags +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label8n.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label8n.tf new file mode 100755 index 0000000..fd4ad57 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label8n.tf @@ -0,0 +1,45 @@ +module "label8n" { + source = "../../" + + enabled = true + namespace = "EG" + environment = "demo" + name = "blue" + attributes = ["eks", "ClusteR"] + delimiter = "-" + label_value_case = "none" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8n_context" { + source = "../../" + + context = module.label8n.context +} + +output "label8n_context_id" { + value = module.label8n_context.id +} + +output "label8n_context_context" { + value = module.label8n_context.context +} + +output "label8n_context_tags" { + value = module.label8n_context.tags +} + +output "label8n_id" { + value = module.label8n.id +} + +output "label8n_context" { + value = module.label8n.context +} + +output "label8n_tags" { + value = module.label8n.tags +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label8t.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label8t.tf new file mode 100755 index 0000000..cb54c7a --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label8t.tf @@ -0,0 +1,45 @@ +module "label8t" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["EKS", "cluster"] + delimiter = "-" + label_key_case = "title" + label_value_case = "title" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8t_context" { + source = "../../" + + context = module.label8t.context +} + +output "label8t_context_id" { + value = module.label8t_context.id +} + +output "label8t_context_context" { + value = module.label8t_context.context +} + +output "label8t_context_tags" { + value = module.label8t_context.tags +} + +output "label8t_id" { + value = module.label8t.id +} + +output "label8t_context" { + value = module.label8t.context +} + +output "label8t_tags" { + value = module.label8t.tags +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label8u.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label8u.tf new file mode 100755 index 0000000..499535b --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/label8u.tf @@ -0,0 +1,50 @@ +module "label8u" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "upper" + label_value_case = "upper" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8u_context" { + source = "../../" + + context = module.label8u.context +} + +output "label8u_context_id" { + value = module.label8u_context.id +} + +output "label8u_context_context" { + value = module.label8u_context.context +} + +// debug +output "label8u_context_normalized_context" { + value = module.label8u_context.normalized_context +} + +output "label8u_context_tags" { + value = module.label8u_context.tags +} + +output "label8u_id" { + value = module.label8u.id +} + +output "label8u_context" { + value = module.label8u.context +} + +output "label8u_tags" { + value = module.label8u.tags +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/versions.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/examples/complete/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/exports/context.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/exports/context.tf new file mode 100755 index 0000000..81f99b4 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/exports/context.tf @@ -0,0 +1,202 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/main.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/main.tf new file mode 100755 index 0000000..0deda2b --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/main.tf @@ -0,0 +1,146 @@ +locals { + + defaults = { + label_order = ["namespace", "environment", "stage", "name", "attributes"] + regex_replace_chars = "/[^-a-zA-Z0-9]/" + delimiter = "-" + replacement = "" + id_length_limit = 0 + id_hash_length = 5 + label_key_case = "title" + label_value_case = "lower" + } + + # So far, we have decided not to allow overriding replacement or id_hash_length + replacement = local.defaults.replacement + id_hash_length = local.defaults.id_hash_length + + # The values provided by variables supersede the values inherited from the context object, + # except for tags and attributes which are merged. + input = { + # It would be nice to use coalesce here, but we cannot, because it + # is an error for all the arguments to coalesce to be empty. + enabled = var.enabled == null ? var.context.enabled : var.enabled + namespace = var.namespace == null ? var.context.namespace : var.namespace + environment = var.environment == null ? var.context.environment : var.environment + stage = var.stage == null ? var.context.stage : var.stage + name = var.name == null ? var.context.name : var.name + delimiter = var.delimiter == null ? var.context.delimiter : var.delimiter + # modules tack on attributes (passed by var) to the end of the list (passed by context) + attributes = compact(distinct(concat(coalesce(var.context.attributes, []), coalesce(var.attributes, [])))) + tags = merge(var.context.tags, var.tags) + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + label_order = var.label_order == null ? var.context.label_order : var.label_order + regex_replace_chars = var.regex_replace_chars == null ? var.context.regex_replace_chars : var.regex_replace_chars + id_length_limit = var.id_length_limit == null ? var.context.id_length_limit : var.id_length_limit + label_key_case = var.label_key_case == null ? lookup(var.context, "label_key_case", null) : var.label_key_case + label_value_case = var.label_value_case == null ? lookup(var.context, "label_value_case", null) : var.label_value_case + } + + + enabled = local.input.enabled + regex_replace_chars = coalesce(local.input.regex_replace_chars, local.defaults.regex_replace_chars) + + # string_label_names are names of inputs that are strings (not list of strings) used as labels + string_label_names = ["name", "namespace", "environment", "stage"] + normalized_labels = { for k in local.string_label_names : k => + local.input[k] == null ? "" : replace(local.input[k], local.regex_replace_chars, local.replacement) + } + normalized_attributes = compact(distinct([for v in local.input.attributes : replace(v, local.regex_replace_chars, local.replacement)])) + + formatted_labels = { for k in local.string_label_names : k => local.label_value_case == "none" ? local.normalized_labels[k] : + local.label_value_case == "title" ? title(lower(local.normalized_labels[k])) : + local.label_value_case == "upper" ? upper(local.normalized_labels[k]) : lower(local.normalized_labels[k]) + } + + attributes = compact(distinct([ + for v in local.normalized_attributes : (local.label_value_case == "none" ? v : + local.label_value_case == "title" ? title(lower(v)) : + local.label_value_case == "upper" ? upper(v) : lower(v)) + ])) + + name = local.formatted_labels["name"] + namespace = local.formatted_labels["namespace"] + environment = local.formatted_labels["environment"] + stage = local.formatted_labels["stage"] + + delimiter = local.input.delimiter == null ? local.defaults.delimiter : local.input.delimiter + label_order = local.input.label_order == null ? local.defaults.label_order : coalescelist(local.input.label_order, local.defaults.label_order) + id_length_limit = local.input.id_length_limit == null ? local.defaults.id_length_limit : local.input.id_length_limit + label_key_case = local.input.label_key_case == null ? local.defaults.label_key_case : local.input.label_key_case + label_value_case = local.input.label_value_case == null ? local.defaults.label_value_case : local.input.label_value_case + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + + tags = merge(local.generated_tags, local.input.tags) + + tags_as_list_of_maps = flatten([ + for key in keys(local.tags) : merge( + { + key = key + value = local.tags[key] + }, var.additional_tag_map) + ]) + + tags_context = { + # For AWS we need `Name` to be disambiguated since it has a special meaning + name = local.id + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = local.id_context.attributes + } + + generated_tags = { + for l in keys(local.tags_context) : + local.label_key_case == "upper" ? upper(l) : ( + local.label_key_case == "lower" ? lower(l) : title(lower(l)) + ) => local.tags_context[l] if length(local.tags_context[l]) > 0 + } + + id_context = { + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = join(local.delimiter, local.attributes) + } + + labels = [for l in local.label_order : local.id_context[l] if length(local.id_context[l]) > 0] + + id_full = join(local.delimiter, local.labels) + # Create a truncated ID if needed + delimiter_length = length(local.delimiter) + # Calculate length of normal part of ID, leaving room for delimiter and hash + id_truncated_length_limit = local.id_length_limit - (local.id_hash_length + local.delimiter_length) + # Truncate the ID and ensure a single (not double) trailing delimiter + id_truncated = local.id_truncated_length_limit <= 0 ? "" : "${trimsuffix(substr(local.id_full, 0, local.id_truncated_length_limit), local.delimiter)}${local.delimiter}" + # Support usages that disallow numeric characters. Would prefer tr 0-9 q-z but Terraform does not support it. + id_hash_plus = "${md5(local.id_full)}qrstuvwxyz" + id_hash_case = local.label_value_case == "title" ? title(local.id_hash_plus) : local.label_value_case == "upper" ? upper(local.id_hash_plus) : local.label_value_case == "lower" ? lower(local.id_hash_plus) : local.id_hash_plus + id_hash = replace(local.id_hash_case, local.regex_replace_chars, local.replacement) + # Create the short ID by adding a hash to the end of the truncated ID + id_short = substr("${local.id_truncated}${local.id_hash}", 0, local.id_length_limit) + id = local.id_length_limit != 0 && length(local.id_full) > local.id_length_limit ? local.id_short : local.id_full + + + # Context of this label to pass to other label modules + output_context = { + enabled = local.enabled + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + delimiter = local.delimiter + attributes = local.attributes + tags = local.tags + additional_tag_map = local.additional_tag_map + label_order = local.label_order + regex_replace_chars = local.regex_replace_chars + id_length_limit = local.id_length_limit + label_key_case = local.label_key_case + label_value_case = local.label_value_case + } + +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/outputs.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/outputs.tf new file mode 100755 index 0000000..87ad1be --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/outputs.tf @@ -0,0 +1,88 @@ +output "id" { + value = local.enabled ? local.id : "" + description = "Disambiguated ID restricted to `id_length_limit` characters in total" +} + +output "id_full" { + value = local.enabled ? local.id_full : "" + description = "Disambiguated ID not restricted in length" +} + +output "enabled" { + value = local.enabled + description = "True if module is enabled, false otherwise" +} + +output "namespace" { + value = local.enabled ? local.namespace : "" + description = "Normalized namespace" +} + +output "environment" { + value = local.enabled ? local.environment : "" + description = "Normalized environment" +} + +output "name" { + value = local.enabled ? local.name : "" + description = "Normalized name" +} + +output "stage" { + value = local.enabled ? local.stage : "" + description = "Normalized stage" +} + +output "delimiter" { + value = local.enabled ? local.delimiter : "" + description = "Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes`" +} + +output "attributes" { + value = local.enabled ? local.attributes : [] + description = "List of attributes" +} + +output "tags" { + value = local.enabled ? local.tags : {} + description = "Normalized Tag map" +} + +output "additional_tag_map" { + value = local.additional_tag_map + description = "The merged additional_tag_map" +} + +output "label_order" { + value = local.label_order + description = "The naming order actually used to create the ID" +} + +output "regex_replace_chars" { + value = local.regex_replace_chars + description = "The regex_replace_chars actually used to create the ID" +} + +output "id_length_limit" { + value = local.id_length_limit + description = "The id_length_limit actually used to create the ID, with `0` meaning unlimited" +} + +output "tags_as_list_of_maps" { + value = local.tags_as_list_of_maps + description = "Additional tags as a list of maps, which can be used in several AWS resources" +} + +output "normalized_context" { + value = local.output_context + description = "Normalized context of this module" +} + +output "context" { + value = local.input + description = <<-EOT + Merged but otherwise unmodified input to this module, to be used as context input to other modules. + Note: this version will have null values as defaults, not the values actually used as defaults. +EOT +} + diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/test/Makefile b/.terraform/modules/datadog_integration.forwarder_rds_label/test/Makefile new file mode 100755 index 0000000..ea15d62 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/test/Makefile @@ -0,0 +1,43 @@ +TEST_HARNESS ?= https://github.com/cloudposse/test-harness.git +TEST_HARNESS_BRANCH ?= master +TEST_HARNESS_PATH = $(realpath .test-harness) +BATS_ARGS ?= --tap +BATS_LOG ?= test.log + +# Define a macro to run the tests +define RUN_TESTS +@echo "Running tests in $(1)" +@cd $(1) && bats $(BATS_ARGS) $(addsuffix .bats,$(addprefix $(TEST_HARNESS_PATH)/test/terraform/,$(TESTS))) +endef + +default: all + +-include Makefile.* + +## Provision the test-harnesss +.test-harness: + [ -d $@ ] || git clone --depth=1 -b $(TEST_HARNESS_BRANCH) $(TEST_HARNESS) $@ + +## Initialize the tests +init: .test-harness + +## Install all dependencies (OS specific) +deps:: + @exit 0 + +## Clean up the test harness +clean: + [ "$(TEST_HARNESS_PATH)" == "/" ] || rm -rf $(TEST_HARNESS_PATH) + +## Run all tests +all: module examples/complete + +## Run basic sanity checks against the module itself +module: export TESTS ?= installed lint get-modules module-pinning get-plugins provider-pinning validate terraform-docs input-descriptions output-descriptions +module: deps + $(call RUN_TESTS, ../) + +## Run tests against example +examples/complete: export TESTS ?= installed lint get-modules get-plugins validate init plan apply +examples/complete: deps + $(call RUN_TESTS, ../$@) diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/test/Makefile.alpine b/.terraform/modules/datadog_integration.forwarder_rds_label/test/Makefile.alpine new file mode 100755 index 0000000..7925b18 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/test/Makefile.alpine @@ -0,0 +1,5 @@ +ifneq (,$(wildcard /sbin/apk)) +## Install all dependencies for alpine +deps:: init + @apk add --update terraform-docs@cloudposse json2hcl@cloudposse +endif diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/test/src/Makefile b/.terraform/modules/datadog_integration.forwarder_rds_label/test/src/Makefile new file mode 100755 index 0000000..b772822 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/test/src/Makefile @@ -0,0 +1,30 @@ +export TF_CLI_ARGS_init ?= -get-plugins=true +export TERRAFORM_VERSION ?= $(shell curl -s https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r -M '.current_version' | cut -d. -f1-2) + +.DEFAULT_GOAL : all +.PHONY: all + +## Default target +all: test + +.PHONY : init +## Initialize tests +init: + @exit 0 + +.PHONY : test +## Run tests +test: init + go mod download + go test -v -timeout 60m -run TestExamplesComplete + +## Run tests in docker container +docker/test: + docker run --name terratest --rm -it -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e GITHUB_TOKEN \ + -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" \ + -v $(CURDIR)/../../:/module/ cloudposse/test-harness:latest -C /module/test/src test + +.PHONY : clean +## Clean up files +clean: + rm -rf ../../examples/complete/*.tfstate* diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/test/src/examples_complete_test.go b/.terraform/modules/datadog_integration.forwarder_rds_label/test/src/examples_complete_test.go new file mode 100755 index 0000000..156e293 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/test/src/examples_complete_test.go @@ -0,0 +1,293 @@ +package test + +import ( + "fmt" + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" + "github.com/qdm12/reprint" + "github.com/stretchr/testify/assert" +) + +type NLContext struct { + AdditionalTagMap map[string]string `json:"additional_tag_map"` + Attributes []string `json:"attributes"` + Delimiter interface{} `json:"delimiter"` + Enabled bool `json:"enabled"` + Environment interface{} `json:"environment"` + LabelOrder []string `json:"label_order"` + Name interface{} `json:"name"` + Namespace interface{} `json:"namespace"` + RegexReplaceChars interface{} `json:"regex_replace_chars"` + Stage interface{} `json:"stage"` + Tags map[string]string `json:"tags"` +} + +// Test the Terraform module in examples/complete using Terratest. +func TestExamplesComplete(t *testing.T) { + t.Parallel() + + terraformOptions := &terraform.Options{ + // The path to where our Terraform code is located + TerraformDir: "../../examples/complete", + Upgrade: true, + } + + // At the end of the test, run `terraform destroy` to clean up any resources that were created + defer terraform.Destroy(t, terraformOptions) + + // This will run `terraform init` and `terraform apply` and fail the test if there are any errors + terraform.InitAndApply(t, terraformOptions) + + expectedLabel1Context := NLContext{ + Enabled: true, + Namespace: "CloudPosse", + Environment: "UAT", + Stage: "build", + Name: "Winston Churchroom", + Attributes: []string{"fire", "water", "earth", "air"}, + Delimiter: "-", + LabelOrder: []string{"name", "environment", "stage", "attributes"}, + Tags: map[string]string{ + "City": "Dublin", + "Environment": "Private", + }, + AdditionalTagMap: map[string]string{}, + } + + var expectedLabel1NormalizedContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel1NormalizedContext) + expectedLabel1NormalizedContext.Namespace = "cloudposse" + expectedLabel1NormalizedContext.Environment = "uat" + expectedLabel1NormalizedContext.Name = "winstonchurchroom" + expectedLabel1NormalizedContext.RegexReplaceChars = "/[^-a-zA-Z0-9]/" + expectedLabel1NormalizedContext.Tags = map[string]string{ + "City": "Dublin", + "Environment": "Private", + "Namespace": "cloudposse", + "Stage": "build", + "Name": "winstonchurchroom-uat-build-fire-water-earth-air", + "Attributes": "fire-water-earth-air", + } + + var label1NormalizedContext, label1Context NLContext + // Run `terraform output` to get the value of an output variable + label1 := terraform.OutputMap(t, terraformOptions, "label1") + label1Tags := terraform.OutputMap(t, terraformOptions, "label1_tags") + terraform.OutputStruct(t, terraformOptions, "label1_normalized_context", &label1NormalizedContext) + terraform.OutputStruct(t, terraformOptions, "label1_context", &label1Context) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1["id"]) + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1Tags["Name"]) + assert.Equal(t, "Dublin", label1Tags["City"]) + assert.Equal(t, "Private", label1Tags["Environment"]) + assert.Equal(t, expectedLabel1NormalizedContext, label1NormalizedContext) + assert.Equal(t, expectedLabel1Context, label1Context) + + label1t1 := terraform.OutputMap(t, terraformOptions, "label1t1") + label1t1Tags := terraform.OutputMap(t, terraformOptions, "label1t1_tags") + assert.Equal(t, "winstonchurchroom-uat-6a0b34", label1t1["id"], + "Extra hash character should be added when trailing delimiter is removed") + assert.Equal(t, label1["id"], label1t1["id_full"], "id_full should not be truncated") + assert.Equal(t, label1t1["id"], label1t1Tags["Name"], "Name tag should match ID") + + label1t2 := terraform.OutputMap(t, terraformOptions, "label1t2") + label1t2Tags := terraform.OutputMap(t, terraformOptions, "label1t2_tags") + assert.Equal(t, "winstonchurchroom-uat-b-6a0b3", label1t2["id"]) + assert.Equal(t, label1t2["id"], label1t2Tags["Name"], "Name tag should match ID") + + // Run `terraform output` to get the value of an output variable + label2 := terraform.OutputMap(t, terraformOptions, "label2") + label2Tags := terraform.OutputMap(t, terraformOptions, "label2_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2["id"]) + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2Tags["Name"]) + assert.Equal(t, "London", label2Tags["City"]) + assert.Equal(t, "Public", label2Tags["Environment"]) + + var expectedLabel3cContext, label3cContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel3cContext) + expectedLabel3cContext.Name = "Starfish" + expectedLabel3cContext.Stage = "release" + expectedLabel3cContext.Delimiter = "." + expectedLabel3cContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3cContext.Tags["Eat"] = "Carrot" + expectedLabel3cContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3c := terraform.OutputMap(t, terraformOptions, "label3c") + label3cTags := terraform.OutputMap(t, terraformOptions, "label3c_tags") + terraform.OutputStruct(t, terraformOptions, "label3c_context", &label3cContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3c["id"]) + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3cTags["Name"]) + assert.Equal(t, expectedLabel3cContext, label3cContext) + + var expectedLabel3nContext, label3nContext NLContext + _ = reprint.FromTo(&expectedLabel1NormalizedContext, &expectedLabel3nContext) + expectedLabel3nContext.Name = "Starfish" + expectedLabel3nContext.Stage = "release" + expectedLabel3nContext.Delimiter = "." + expectedLabel3nContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3nContext.Tags["Eat"] = "Carrot" + expectedLabel3nContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3n := terraform.OutputMap(t, terraformOptions, "label3n") + label3nTags := terraform.OutputMap(t, terraformOptions, "label3n_tags") + terraform.OutputStruct(t, terraformOptions, "label3n_context", &label3nContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3n["id"]) + assert.Equal(t, label1Tags["Name"], label3nTags["Name"], + "Tag from label1 normalized context should overwrite label3n generated tag") + assert.Equal(t, expectedLabel3nContext, label3nContext) + + // Run `terraform output` to get the value of an output variable + label4 := terraform.OutputMap(t, terraformOptions, "label4") + label4Tags := terraform.OutputMap(t, terraformOptions, "label4_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4["id"]) + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4Tags["Name"]) + + // Run `terraform output` to get the value of an output variable + label5 := terraform.OutputMap(t, terraformOptions, "label5") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "", label5["id"]) + + label6f := terraform.OutputMap(t, terraformOptions, "label6f") + label6fTags := terraform.OutputMap(t, terraformOptions, "label6f_tags") + // Test of setting var.label_key_case = "lower", var.label_value_case = "upper" + assert.Equal(t, "CP~UW2~PRD~NULL-LABEL", label6f["id_full"]) + assert.Equal(t, label6f["id_full"], label6f["id"], "id should not be truncated") + assert.Equal(t, label6f["id"], label6fTags["name"], "Name tag should match ID") + + label6t := terraform.OutputMap(t, terraformOptions, "label6t") + label6tTags := terraform.OutputMap(t, terraformOptions, "label6t_tags") + assert.Equal(t, "CPUW2PRDNULL-LABEL", label6t["id_full"]) + assert.NotEqual(t, label6t["id_full"], label6t["id"], "id should be truncated") + assert.Equal(t, label6t["id"], label6tTags["name"], "Name tag should match ID") + assert.Equal(t, label6t["id_length_limit"], fmt.Sprintf("%d", len(label6t["id"])), + "Truncated ID length should equal length limit") + + label7 := terraform.OutputMap(t, terraformOptions, "label7") + assert.Equal(t, "eg-demo-blue-cluster-nodegroup", label7["id"], "var.attributes should be appended after context.attributes") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter=""` returns expected value of id, context id + label8dndID := terraform.Output(t, terraformOptions, "label8dnd_id") + label8dndContextID := terraform.Output(t, terraformOptions, "label8dnd_context_id") + assert.Equal(t, "egdemobluecluster", label8dndID) + assert.Equal(t, label8dndID, label8dndContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter="x"` returns expected value of id, context id + label8dcdID := terraform.Output(t, terraformOptions, "label8dcd_id") + label8dcdContextID := terraform.Output(t, terraformOptions, "label8dcd_context_id") + assert.Equal(t, "egxdemoxbluexcluster", label8dcdID) + assert.Equal(t, label8dcdID, label8dcdContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=lower` returns expected values of id, tags, context tags + label8dExpectedTags := map[string]string{ + "Attributes": "cluster", + "Environment": "demo", + "Name": "eg-demo-blue-cluster", + "Namespace": "eg", + "kubernetes.io/cluster/": "shared", + } + + label8dID := terraform.Output(t, terraformOptions, "label8d_id") + label8dContextID := terraform.Output(t, terraformOptions, "label8d_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8dID) + assert.Equal(t, label8dID, label8dContextID, "ID and context ID should be equal") + + label8dTags := terraform.OutputMap(t, terraformOptions, "label8d_tags") + label8dContextTags := terraform.OutputMap(t, terraformOptions, "label8d_context_tags") + + assert.Exactly(t, label8dExpectedTags, label8dTags, "generated tags are different from expected") + assert.Exactly(t, label8dTags, label8dContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=lower` and `label_value_case=lower` returns expected values of id, tags, context tags + label8lExpectedTags := map[string]string{ + "attributes": "cluster", + "environment": "demo", + "name": "eg-demo-blue-cluster", + "namespace": "eg", + "kubernetes.io/cluster/": "shared", + "upperTEST": "testUPPER", + } + + label8lID := terraform.Output(t, terraformOptions, "label8l_id") + label8lContextID := terraform.Output(t, terraformOptions, "label8l_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8lID) + assert.Equal(t, label8lID, label8lContextID, "ID and context ID should be equal") + + label8lTags := terraform.OutputMap(t, terraformOptions, "label8l_tags") + label8lContextTags := terraform.OutputMap(t, terraformOptions, "label8l_context_tags") + + assert.Exactly(t, label8lExpectedTags, label8lTags, "generated tags are different from expected") + assert.Exactly(t, label8lTags, label8lContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=title` returns expected values of id, tags, context tags + label8tExpectedTags := map[string]string{ + "Attributes": "Eks-Cluster", + "Environment": "Demo", + "Name": "Eg-Demo-Blue-Eks-Cluster", + "Namespace": "Eg", + "kubernetes.io/cluster/": "shared", + } + + label8tID := terraform.Output(t, terraformOptions, "label8t_id") + label8tContextID := terraform.Output(t, terraformOptions, "label8t_context_id") + assert.Equal(t, "Eg-Demo-Blue-Eks-Cluster", label8tID) + assert.Equal(t, label8tID, label8tContextID, "ID and context ID should be equal") + + label8tTags := terraform.OutputMap(t, terraformOptions, "label8t_tags") + label8tContextTags := terraform.OutputMap(t, terraformOptions, "label8t_context_tags") + + assert.Exactly(t, label8tExpectedTags, label8tTags, "generated tags are different from expected") + assert.Exactly(t, label8tTags, label8tContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=upper` and `label_value_case=upper` returns expected values of id, tags, context tags + label8uExpectedTags := map[string]string{ + "ATTRIBUTES": "CLUSTER", + "ENVIRONMENT": "DEMO", + "NAME": "EG-DEMO-BLUE-CLUSTER", + "NAMESPACE": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8uID := terraform.Output(t, terraformOptions, "label8u_id") + label8uContextID := terraform.Output(t, terraformOptions, "label8u_context_id") + assert.Equal(t, "EG-DEMO-BLUE-CLUSTER", label8uID) + assert.Equal(t, label8uID, label8uContextID, "ID and context ID should be equal") + + label8uTags := terraform.OutputMap(t, terraformOptions, "label8u_tags") + label8uContextTags := terraform.OutputMap(t, terraformOptions, "label8u_context_tags") + + assert.Exactly(t, label8uExpectedTags, label8uTags, "generated tags are different from expected") + assert.Exactly(t, label8uTags, label8uContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=none` returns expected values of id, tags, context tags + label8nExpectedTags := map[string]string{ + "Attributes": "eks-ClusteR", + "Environment": "demo", + "Name": "EG-demo-blue-eks-ClusteR", + "Namespace": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8nID := terraform.Output(t, terraformOptions, "label8n_id") + label8nContextID := terraform.Output(t, terraformOptions, "label8n_context_id") + assert.Equal(t, "EG-demo-blue-eks-ClusteR", label8nID) + assert.Equal(t, label8nID, label8nContextID, "ID and context ID should be equal") + + label8nTags := terraform.OutputMap(t, terraformOptions, "label8n_tags") + label8nContextTags := terraform.OutputMap(t, terraformOptions, "label8n_context_tags") + + assert.Exactly(t, label8nExpectedTags, label8nTags, "generated tags are different from expected") + assert.Exactly(t, label8nTags, label8nContextTags, "tags and context tags should be equal") +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/test/src/go.mod b/.terraform/modules/datadog_integration.forwarder_rds_label/test/src/go.mod new file mode 100755 index 0000000..d866541 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/test/src/go.mod @@ -0,0 +1,9 @@ +module github.com/cloudposse/terraform-null-label + +go 1.14 + +require ( + github.com/gruntwork-io/terratest v0.31.1 + github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 + github.com/stretchr/testify v1.6.1 +) diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/test/src/go.sum b/.terraform/modules/datadog_integration.forwarder_rds_label/test/src/go.sum new file mode 100755 index 0000000..b8d46b1 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/test/src/go.sum @@ -0,0 +1,595 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= +github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.5/go.mod h1:foo3aIXRQ90zFve3r0QiDsrjGDUwWhKl0ZOQy1CT14k= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= +github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200109221225-a4f60165b7a3/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= +github.com/gruntwork-io/terratest v0.31.1 h1:MPGe/5pGgJAIZ/hb+0LM1KyJKSi/QyxSkHoP9/CBhJg= +github.com/gruntwork-io/terratest v0.31.1/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= +github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4= +github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= +github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= +k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= +k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= +k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= +k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= +k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= +k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= +k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= +modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/variables.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/variables.tf new file mode 100755 index 0000000..40fb268 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/variables.tf @@ -0,0 +1,157 @@ +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} diff --git a/.terraform/modules/datadog_integration.forwarder_rds_label/versions.tf b/.terraform/modules/datadog_integration.forwarder_rds_label/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration.forwarder_rds_label/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration.lambda_label/LICENSE b/.terraform/modules/datadog_integration.lambda_label/LICENSE new file mode 100755 index 0000000..c844c70 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017-2020 Cloud Posse, LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/.terraform/modules/datadog_integration.lambda_label/Makefile b/.terraform/modules/datadog_integration.lambda_label/Makefile new file mode 100755 index 0000000..97d8087 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/Makefile @@ -0,0 +1,10 @@ +SHELL := /bin/bash + +# List of targets the `readme` target should call before generating the readme +export README_DEPS ?= docs/targets.md docs/terraform.md + +-include $(shell curl -sSL -o .build-harness "https://git.io/build-harness"; echo .build-harness) + +## Lint terraform code +lint: + $(SELF) terraform/install terraform/get-modules terraform/get-plugins terraform/lint terraform/validate diff --git a/.terraform/modules/datadog_integration.lambda_label/README.md b/.terraform/modules/datadog_integration.lambda_label/README.md new file mode 100755 index 0000000..32950e4 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/README.md @@ -0,0 +1,938 @@ + +# terraform-null-label [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-null-label.svg)](https://github.com/cloudposse/terraform-null-label/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) + + +[![README Header][readme_header_img]][readme_header_link] + +[![Cloud Posse][logo]](https://cpco.io/homepage) + + + +Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + +This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. +However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). +So if you prefer the term `stage` to `environment` +you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. +- If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. +- If you want the attributes in a different order, you can specify that, too, with the `label_order` list. +- You can set a maximum length for the name, and the module will create a unique name that fits within that length. +- You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. +- The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + +It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. +For example, if you have 10 instances, there should be 10 different labels. +However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + +All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + +**NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. +With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + +- Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. +- Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. +- Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. + + +--- + +This project is part of our comprehensive ["SweetOps"](https://cpco.io/sweetops) approach towards DevOps. +[][share_email] +[][share_googleplus] +[][share_facebook] +[][share_reddit] +[][share_linkedin] +[][share_twitter] + + +[![Terraform Open Source Modules](https://docs.cloudposse.com/images/terraform-open-source-modules.svg)][terraform_modules] + + + +It's 100% Open Source and licensed under the [APACHE2](LICENSE). + + + + + + + +We literally have [*hundreds of terraform modules*][terraform_modules] that are Open Source and well-maintained. Check them out! + + + + + + + +## Security & Compliance [](https://bridgecrew.io/) + +Security scanning is graciously provided by Bridgecrew. Bridgecrew is the leading fully hosted, cloud-native solution providing continuous Terraform security and compliance. + +| Benchmark | Description | +|--------|---------------| +| [![Infrastructure Security](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/general)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=INFRASTRUCTURE+SECURITY) | Infrastructure Security Compliance | +| [![CIS KUBERNETES](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_kubernetes)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+KUBERNETES+V1.5) | Center for Internet Security, KUBERNETES Compliance | +| [![CIS AWS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_aws)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AWS+V1.2) | Center for Internet Security, AWS Compliance | +| [![CIS AZURE](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_azure)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AZURE+V1.1) | Center for Internet Security, AZURE Compliance | +| [![PCI-DSS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/pci)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=PCI-DSS+V3.2) | Payment Card Industry Data Security Standards Compliance | +| [![NIST-800-53](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/nist)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=NIST-800-53) | National Institute of Standards and Technology Compliance | +| [![ISO27001](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/iso)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=ISO27001) | Information Security Management System, ISO/IEC 27001 Compliance | +| [![SOC2](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/soc2)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=SOC2)| Service Organization Control 2 Compliance | +| [![CIS GCP](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_gcp)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+GCP+V1.1) | Center for Internet Security, GCP Compliance | +| [![HIPAA](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/hipaa)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=HIPAA) | Health Insurance Portability and Accountability Compliance | + + + +## Usage + + +**IMPORTANT:** We do not pin modules to versions in our examples because of the +difficulty of keeping the versions in the documentation in sync with the latest released versions. +We highly recommend that in your code you pin the version to the exact version you are +using so that your infrastructure remains stable, and update versions in a +systematic way so that they do not catch you by surprise. + +Also, because of a bug in the Terraform registry ([hashicorp/terraform#21417](https://github.com/hashicorp/terraform/issues/21417)), +the registry shows many of our inputs as required when in fact they are optional. +The table below correctly indicates which inputs are required. + + +### Defaults + +Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. +The context object is a single object that contains all the input values for `terraform-null-label`. +However, each input value can also be specified individually by name as a standard Terraform variable, +and the value of those variables, when set to something other than `null`, will override the value +in the context object. In order to allow chaining of these objects, where the context object input to one +module is transformed and passed to the next module, all the variables default to `null` or empty collections. +The actual default values used when nothing is explicitly set are describe in the documentation below. + +For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, +`terraform-null-label` will actually use the default delimiter `-` (hyphen). + +A non-obvious but intentional consequence of this design is that once a module sets a non-default value, +future modules in the chain cannot reset the value back to the original default. Insted, the new setting +becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, +so once a tag is added, it will remain in the tag set and cannot be removed, although its value can +be overwritten. + +### Simple Example + +```hcl +module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} +``` + +This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` +(you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + +Now reference the label when creating an instance: + +```hcl +resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags +} +``` + +Or define a security group: + +```hcl +resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} +``` + + +### Advanced Example + +Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + +```hcl +module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] +} + +module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] +} +``` + +
+ +### Advanced Example 2 + +Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + +```hcl +tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } +] +``` + +Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + +```hcl +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} +``` + +
+ +### Advanced Example 3 + +See [complete example](./examples/complete) for even more examples. + +This example shows how you can pass the `context` output of one label module to the next label_module, +allowing you to create one label that has the base set of values, and then creating every extra label +as a derivative of that. + +
Click to show + +```hcl +module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} +``` + +This creates label outputs like this: + +```hcl +label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" +} +label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } +} +label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } +} +label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" +} +label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" +} +label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } +} +label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" +} +label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, +] +label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" +} +label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } +} +label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } +} +label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" +} + +``` + +
+ + + + + + + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + + + + +## Share the Love + +Like this project? Please give it a ★ on [our GitHub](https://github.com/cloudposse/terraform-null-label)! (it helps us **a lot**) + +Are you using this project or any of our other projects? Consider [leaving a testimonial][testimonial]. =) + + +## Related Projects + +Check out these related projects. + +- [terraform-terraform-label](https://github.com/cloudposse/terraform-terraform-label) - Terraform Module to define a consistent naming convention by (namespace, environment, stage, name, [attributes]) + + + +## Help + +**Got a question?** We got answers. + +File a GitHub [issue](https://github.com/cloudposse/terraform-null-label/issues), send us an [email][email] or join our [Slack Community][slack]. + +[![README Commercial Support][readme_commercial_support_img]][readme_commercial_support_link] + +## DevOps Accelerator for Startups + + +We are a [**DevOps Accelerator**][commercial_support]. We'll help you build your cloud infrastructure from the ground up so you can own it. Then we'll show you how to operate it and stick around for as long as you need us. + +[![Learn More](https://img.shields.io/badge/learn%20more-success.svg?style=for-the-badge)][commercial_support] + +Work directly with our team of DevOps experts via email, slack, and video conferencing. + +We deliver 10x the value for a fraction of the cost of a full-time engineer. Our track record is not even funny. If you want things done right and you need it done FAST, then we're your best bet. + +- **Reference Architecture.** You'll get everything you need from the ground up built using 100% infrastructure as code. +- **Release Engineering.** You'll have end-to-end CI/CD with unlimited staging environments. +- **Site Reliability Engineering.** You'll have total visibility into your apps and microservices. +- **Security Baseline.** You'll have built-in governance with accountability and audit logs for all changes. +- **GitOps.** You'll be able to operate your infrastructure via Pull Requests. +- **Training.** You'll receive hands-on training so your team can operate what we build. +- **Questions.** You'll have a direct line of communication between our teams via a Shared Slack channel. +- **Troubleshooting.** You'll get help to triage when things aren't working. +- **Code Reviews.** You'll receive constructive feedback on Pull Requests. +- **Bug Fixes.** We'll rapidly work with you to fix any bugs in our projects. + +## Slack Community + +Join our [Open Source Community][slack] on Slack. It's **FREE** for everyone! Our "SweetOps" community is where you get to talk with others who share a similar vision for how to rollout and manage infrastructure. This is the best place to talk shop, ask questions, solicit feedback, and work together as a community to build totally *sweet* infrastructure. + +## Discourse Forums + +Participate in our [Discourse Forums][discourse]. Here you'll find answers to commonly asked questions. Most questions will be related to the enormous number of projects we support on our GitHub. Come here to collaborate on answers, find solutions, and get ideas about the products and services we value. It only takes a minute to get started! Just sign in with SSO using your GitHub account. + +## Newsletter + +Sign up for [our newsletter][newsletter] that covers everything on our technology radar. Receive updates on what we're up to on GitHub as well as awesome new projects we discover. + +## Office Hours + +[Join us every Wednesday via Zoom][office_hours] for our weekly "Lunch & Learn" sessions. It's **FREE** for everyone! + +[![zoom](https://img.cloudposse.com/fit-in/200x200/https://cloudposse.com/wp-content/uploads/2019/08/Powered-by-Zoom.png")][office_hours] + +## Contributing + +### Bug Reports & Feature Requests + +Please use the [issue tracker](https://github.com/cloudposse/terraform-null-label/issues) to report any bugs or file feature requests. + +### Developing + +If you are interested in being a contributor and want to get involved in developing this project or [help out](https://cpco.io/help-out) with our other projects, we would love to hear from you! Shoot us an [email][email]. + +In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. + + 1. **Fork** the repo on GitHub + 2. **Clone** the project to your own machine + 3. **Commit** changes to your own branch + 4. **Push** your work back up to your fork + 5. Submit a **Pull Request** so that we can review your changes + +**NOTE:** Be sure to merge the latest changes from "upstream" before making a pull request! + + +## Copyright + +Copyright © 2017-2021 [Cloud Posse, LLC](https://cpco.io/copyright) + + + +## License + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +See [LICENSE](LICENSE) for full details. + +```text +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +``` + + + + + + + + + +## Trademarks + +All other trademarks referenced herein are the property of their respective owners. + +## About + +This project is maintained and funded by [Cloud Posse, LLC][website]. Like it? Please let us know by [leaving a testimonial][testimonial]! + +[![Cloud Posse][logo]][website] + +We're a [DevOps Professional Services][hire] company based in Los Angeles, CA. We ❤️ [Open Source Software][we_love_open_source]. + +We offer [paid support][commercial_support] on all of our projects. + +Check out [our other projects][github], [follow us on twitter][twitter], [apply for a job][jobs], or [hire us][hire] to help with your cloud strategy and implementation. + + + +### Contributors + + +| [![Erik Osterman][osterman_avatar]][osterman_homepage]
[Erik Osterman][osterman_homepage] | [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]
[Andriy Knysh][aknysh_homepage] | [![Igor Rodionov][goruha_avatar]][goruha_homepage]
[Igor Rodionov][goruha_homepage] | [![Sergey Vasilyev][s2504s_avatar]][s2504s_homepage]
[Sergey Vasilyev][s2504s_homepage] | [![Michael Pereira][MichaelPereira_avatar]][MichaelPereira_homepage]
[Michael Pereira][MichaelPereira_homepage] | [![Jamie Nelson][Jamie-BitFlight_avatar]][Jamie-BitFlight_homepage]
[Jamie Nelson][Jamie-BitFlight_homepage] | [![Vladimir][SweetOps_avatar]][SweetOps_homepage]
[Vladimir][SweetOps_homepage] | [![Daren Desjardins][darend_avatar]][darend_homepage]
[Daren Desjardins][darend_homepage] | [![Maarten van der Hoef][maartenvanderhoef_avatar]][maartenvanderhoef_homepage]
[Maarten van der Hoef][maartenvanderhoef_homepage] | [![Adam Tibbing][tibbing_avatar]][tibbing_homepage]
[Adam Tibbing][tibbing_homepage] | +|---|---|---|---|---|---|---|---|---|---| + + + [osterman_homepage]: https://github.com/osterman + [osterman_avatar]: https://img.cloudposse.com/150x150/https://github.com/osterman.png + [aknysh_homepage]: https://github.com/aknysh + [aknysh_avatar]: https://img.cloudposse.com/150x150/https://github.com/aknysh.png + [goruha_homepage]: https://github.com/goruha + [goruha_avatar]: https://img.cloudposse.com/150x150/https://github.com/goruha.png + [s2504s_homepage]: https://github.com/s2504s + [s2504s_avatar]: https://img.cloudposse.com/150x150/https://github.com/s2504s.png + [MichaelPereira_homepage]: https://github.com/MichaelPereira + [MichaelPereira_avatar]: https://img.cloudposse.com/150x150/https://github.com/MichaelPereira.png + [Jamie-BitFlight_homepage]: https://github.com/Jamie-BitFlight + [Jamie-BitFlight_avatar]: https://img.cloudposse.com/150x150/https://github.com/Jamie-BitFlight.png + [SweetOps_homepage]: https://github.com/SweetOps + [SweetOps_avatar]: https://img.cloudposse.com/150x150/https://github.com/SweetOps.png + [darend_homepage]: https://github.com/darend + [darend_avatar]: https://img.cloudposse.com/150x150/https://github.com/darend.png + [maartenvanderhoef_homepage]: https://github.com/maartenvanderhoef + [maartenvanderhoef_avatar]: https://img.cloudposse.com/150x150/https://github.com/maartenvanderhoef.png + [tibbing_homepage]: https://github.com/tibbing + [tibbing_avatar]: https://img.cloudposse.com/150x150/https://github.com/tibbing.png + +[![README Footer][readme_footer_img]][readme_footer_link] +[![Beacon][beacon]][website] + + [logo]: https://cloudposse.com/logo-300x69.svg + [docs]: https://cpco.io/docs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=docs + [website]: https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=website + [github]: https://cpco.io/github?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=github + [jobs]: https://cpco.io/jobs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=jobs + [hire]: https://cpco.io/hire?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=hire + [slack]: https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=slack + [linkedin]: https://cpco.io/linkedin?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=linkedin + [twitter]: https://cpco.io/twitter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=twitter + [testimonial]: https://cpco.io/leave-testimonial?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=testimonial + [office_hours]: https://cloudposse.com/office-hours?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=office_hours + [newsletter]: https://cpco.io/newsletter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=newsletter + [discourse]: https://ask.sweetops.com/?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=discourse + [email]: https://cpco.io/email?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=email + [commercial_support]: https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=commercial_support + [we_love_open_source]: https://cpco.io/we-love-open-source?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=we_love_open_source + [terraform_modules]: https://cpco.io/terraform-modules?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=terraform_modules + [readme_header_img]: https://cloudposse.com/readme/header/img + [readme_header_link]: https://cloudposse.com/readme/header/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_header_link + [readme_footer_img]: https://cloudposse.com/readme/footer/img + [readme_footer_link]: https://cloudposse.com/readme/footer/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_footer_link + [readme_commercial_support_img]: https://cloudposse.com/readme/commercial-support/img + [readme_commercial_support_link]: https://cloudposse.com/readme/commercial-support/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_commercial_support_link + [share_twitter]: https://twitter.com/intent/tweet/?text=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_linkedin]: https://www.linkedin.com/shareArticle?mini=true&title=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_reddit]: https://reddit.com/submit/?url=https://github.com/cloudposse/terraform-null-label + [share_facebook]: https://facebook.com/sharer/sharer.php?u=https://github.com/cloudposse/terraform-null-label + [share_googleplus]: https://plus.google.com/share?url=https://github.com/cloudposse/terraform-null-label + [share_email]: mailto:?subject=terraform-null-label&body=https://github.com/cloudposse/terraform-null-label + [beacon]: https://ga-beacon.cloudposse.com/UA-76589703-4/cloudposse/terraform-null-label?pixel&cs=github&cm=readme&an=terraform-null-label diff --git a/.terraform/modules/datadog_integration.lambda_label/README.yaml b/.terraform/modules/datadog_integration.lambda_label/README.yaml new file mode 100755 index 0000000..42bdb84 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/README.yaml @@ -0,0 +1,618 @@ +name: terraform-null-label +tags: +- aws +- terraform +- terraform-modules +- naming-convention +- name +- namespace +- stage +categories: +- terraform-modules/supported +license: APACHE2 +github_repo: cloudposse/terraform-null-label +badges: +- name: Latest Release + image: https://img.shields.io/github/release/cloudposse/terraform-null-label.svg + url: https://github.com/cloudposse/terraform-null-label/releases/latest +- name: Slack Community + image: https://slack.cloudposse.com/badge.svg + url: https://slack.cloudposse.com +related: +- name: terraform-terraform-label + description: Terraform Module to define a consistent naming convention by (namespace, + environment, stage, name, [attributes]) + url: https://github.com/cloudposse/terraform-terraform-label +description: |- + Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + + This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. + However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). + So if you prefer the term `stage` to `environment` + you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. + - If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. + - If you want the attributes in a different order, you can specify that, too, with the `label_order` list. + - You can set a maximum length for the name, and the module will create a unique name that fits within that length. + - You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. + - The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + + It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. + For example, if you have 10 instances, there should be 10 different labels. + However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + + All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + + **NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. + With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + + - Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. + - Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. + - Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. +usage: |- + ### Defaults + + Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. + The context object is a single object that contains all the input values for `terraform-null-label`. + However, each input value can also be specified individually by name as a standard Terraform variable, + and the value of those variables, when set to something other than `null`, will override the value + in the context object. In order to allow chaining of these objects, where the context object input to one + module is transformed and passed to the next module, all the variables default to `null` or empty collections. + The actual default values used when nothing is explicitly set are describe in the documentation below. + + For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, + `terraform-null-label` will actually use the default delimiter `-` (hyphen). + + A non-obvious but intentional consequence of this design is that once a module sets a non-default value, + future modules in the chain cannot reset the value back to the original default. Insted, the new setting + becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, + so once a tag is added, it will remain in the tag set and cannot be removed, although its value can + be overwritten. + + ### Simple Example + + ```hcl + module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + ``` + + This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` + (you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + + Now reference the label when creating an instance: + + ```hcl + resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags + } + ``` + + Or define a security group: + + ```hcl + resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + } + ``` + + + ### Advanced Example + + Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + + ```hcl + module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] + } + + module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] + } + ``` + +
+ + ### Advanced Example 2 + + Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + + ```hcl + tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } + ] + ``` + + Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + + ```hcl + ################################ + # terraform-null-label example # + ################################ + module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } + } + + ####################### + # Launch template # + ####################### + resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } + } + + ###################### + # Autoscaling group # + ###################### + resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps + } + ``` + +
+ + ### Advanced Example 3 + + See [complete example](./examples/complete) for even more examples. + + This example shows how you can pass the `context` output of one label module to the next label_module, + allowing you to create one label that has the base set of values, and then creating every extra label + as a derivative of that. + +
Click to show + + ```hcl + module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } + } + + module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } + } + + module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } + } + ``` + + This creates label outputs like this: + + ```hcl + label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" + } + label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } + } + label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + } + label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" + } + label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } + } + label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" + } + label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, + ] + label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" + } + label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } + } + label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + } + label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + + ``` + +
+ +include: +- docs/targets.md +- docs/terraform.md +contributors: +- name: Erik Osterman + github: osterman +- name: Andriy Knysh + github: aknysh +- name: Igor Rodionov + github: goruha +- name: Sergey Vasilyev + github: s2504s +- name: Michael Pereira + github: MichaelPereira +- name: Jamie Nelson + github: Jamie-BitFlight +- name: Vladimir + github: SweetOps +- name: Daren Desjardins + github: darend +- name: Maarten van der Hoef + github: maartenvanderhoef +- name: Adam Tibbing + github: tibbing diff --git a/.terraform/modules/datadog_integration.lambda_label/docs/targets.md b/.terraform/modules/datadog_integration.lambda_label/docs/targets.md new file mode 100755 index 0000000..3dce8b3 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/docs/targets.md @@ -0,0 +1,12 @@ + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + diff --git a/.terraform/modules/datadog_integration.lambda_label/docs/terraform.md b/.terraform/modules/datadog_integration.lambda_label/docs/terraform.md new file mode 100755 index 0000000..d4f48f4 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/docs/terraform.md @@ -0,0 +1,54 @@ + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars b/.terraform/modules/datadog_integration.lambda_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars new file mode 100755 index 0000000..f7c725f --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars @@ -0,0 +1,12 @@ +namespace = "eg" +stage = "prod" +name = "app" + +tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" +} + +additional_tag_map = { + propagate_at_launch = "true" +} diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/autoscalinggroup/context.tf b/.terraform/modules/datadog_integration.lambda_label/examples/autoscalinggroup/context.tf new file mode 100755 index 0000000..b97f05f --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/autoscalinggroup/context.tf @@ -0,0 +1,216 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/autoscalinggroup/main.tf b/.terraform/modules/datadog_integration.lambda_label/examples/autoscalinggroup/main.tf new file mode 100755 index 0000000..f0d3aa6 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/autoscalinggroup/main.tf @@ -0,0 +1,104 @@ +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + + context = module.this.context +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template { + id = aws_launch_template.default.id + version = "$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} + +################################ +# Provider # +################################ +provider "aws" { + region = "eu-west-1" + + # Make it faster by skipping unneeded checks here + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +############################################################## +# Data sources to get VPC, subnets and security group details +############################################################## +data "aws_vpc" "default" { + default = true +} + +data "aws_subnet_ids" "all" { + vpc_id = data.aws_vpc.default.id +} + +data "aws_security_group" "default" { + vpc_id = data.aws_vpc.default.id + name = "default" +} + +data "aws_ami" "amazon_linux" { + most_recent = true + + owners = ["amazon"] + + filter { + name = "name" + + values = [ + "amzn-ami-hvm-*-x86_64-gp2", + ] + } + + filter { + name = "owner-alias" + + values = [ + "amazon", + ] + } +} + diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/autoscalinggroup/outputs.tf b/.terraform/modules/datadog_integration.lambda_label/examples/autoscalinggroup/outputs.tf new file mode 100755 index 0000000..f8fcce5 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/autoscalinggroup/outputs.tf @@ -0,0 +1,12 @@ +# terraform-null-label example used here: Output list of tags applied in each format +output "tags_as_list_of_maps" { + value = module.label.tags_as_list_of_maps +} + +output "tags" { + value = module.label.tags +} + +output "id" { + value = module.label.id +} diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/autoscalinggroup/versions.tf b/.terraform/modules/datadog_integration.lambda_label/examples/autoscalinggroup/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/autoscalinggroup/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/complete/complete.auto.tfvars b/.terraform/modules/datadog_integration.lambda_label/examples/complete/complete.auto.tfvars new file mode 100755 index 0000000..e7bc519 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/complete/complete.auto.tfvars @@ -0,0 +1,10 @@ +namespace = "cp" +environment = "uw2" +stage = "prd" +name = "null-label" + +delimiter = "" +id_length_limit = 6 + +label_key_case = "lower" +label_value_case = "upper" diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/complete/context.tf b/.terraform/modules/datadog_integration.lambda_label/examples/complete/context.tf new file mode 100755 index 0000000..973d4dc --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/complete/context.tf @@ -0,0 +1,217 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/complete/label1.tf b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label1.tf new file mode 100755 index 0000000..8da353b --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label1.tf @@ -0,0 +1,42 @@ +module "label1" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label1" { + value = { + id = module.label1.id + name = module.label1.name + namespace = module.label1.namespace + stage = module.label1.stage + attributes = module.label1.attributes + delimiter = module.label1.delimiter + } +} + +output "label1_tags" { + value = module.label1.tags +} + +output "label1_context" { + value = module.label1.context +} + +output "label1_normalized_context" { + value = module.label1.normalized_context +} + + + diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/complete/label1t1.tf b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label1t1.tf new file mode 100755 index 0000000..2bcb362 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label1t1.tf @@ -0,0 +1,18 @@ +module "label1t1" { + source = "../../" + + id_length_limit = 28 + + context = module.label1.context +} + +output "label1t1" { + value = { + id = module.label1t1.id + id_full = module.label1t1.id_full + } +} + +output "label1t1_tags" { + value = module.label1t1.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/complete/label1t2.tf b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label1t2.tf new file mode 100755 index 0000000..5df651e --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label1t2.tf @@ -0,0 +1,18 @@ +module "label1t2" { + source = "../../" + + id_length_limit = 29 + + context = module.label1.context +} + +output "label1t2" { + value = { + id = module.label1t2.id + id_full = module.label1t2.id_full + } +} + +output "label1t2_tags" { + value = module.label1t2.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/complete/label2.tf b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label2.tf new file mode 100755 index 0000000..faf7450 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label2.tf @@ -0,0 +1,42 @@ +module "label2" { + source = "../../" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + regex_replace_chars = "/[^a-zA-Z0-9-+]/" + + additional_tag_map = { + propagate_at_launch = "true" + additional_tag = "yes" + } + + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +output "label2" { + value = { + id = module.label2.id + name = module.label2.name + namespace = module.label2.namespace + stage = module.label2.stage + attributes = module.label2.attributes + delimiter = module.label2.delimiter + } +} + +output "label2_tags" { + value = module.label2.tags +} + +output "label2_tags_as_list_of_maps" { + value = module.label2.tags_as_list_of_maps +} + +output "label2_context" { + value = module.label2.context +} diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/complete/label3c.tf b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label3c.tf new file mode 100755 index 0000000..338a636 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label3c.tf @@ -0,0 +1,36 @@ +module "label3c" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3c" { + value = { + id = module.label3c.id + name = module.label3c.name + namespace = module.label3c.namespace + stage = module.label3c.stage + attributes = module.label3c.attributes + delimiter = module.label3c.delimiter + } +} + +output "label3c_tags" { + value = module.label3c.tags +} + +output "label3c_context" { + value = module.label3c.context +} + +output "label3c_normalized_context" { + value = module.label3c.normalized_context +} diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/complete/label3n.tf b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label3n.tf new file mode 100755 index 0000000..ca51282 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label3n.tf @@ -0,0 +1,36 @@ +module "label3n" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.normalized_context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3n" { + value = { + id = module.label3n.id + name = module.label3n.name + namespace = module.label3n.namespace + stage = module.label3n.stage + attributes = module.label3n.attributes + delimiter = module.label3n.delimiter + } +} + +output "label3n_tags" { + value = module.label3n.tags +} + +output "label3n_context" { + value = module.label3n.context +} + +output "label3n_normalized_context" { + value = module.label3n.normalized_context +} diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/complete/label4.tf b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label4.tf new file mode 100755 index 0000000..74e3ca1 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label4.tf @@ -0,0 +1,34 @@ +module "label4" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + name = "Example Cluster" + attributes = ["big", "fat", "honking", "cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label4" { + value = { + id = module.label4.id + name = module.label4.name + namespace = module.label4.namespace + stage = module.label4.stage + attributes = module.label4.attributes + delimiter = module.label4.delimiter + } +} + +output "label4_tags" { + value = module.label4.tags +} + +output "label4_context" { + value = module.label4.context +} diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/complete/label5.tf b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label5.tf new file mode 100755 index 0000000..0f0a76e --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label5.tf @@ -0,0 +1,33 @@ +module "label5" { + source = "../../" + enabled = false + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + } +} + +output "label5" { + value = { + id = module.label5.id + name = module.label5.name + namespace = module.label5.namespace + stage = module.label5.stage + attributes = module.label5.attributes + delimiter = module.label5.delimiter + } +} + +output "label5_tags" { + value = module.label5.tags +} + +output "label5_context" { + value = module.label5.context +} diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/complete/label6f.tf b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label6f.tf new file mode 100755 index 0000000..1ce1bab --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label6f.tf @@ -0,0 +1,20 @@ +module "label6f" { + source = "../../" + + delimiter = "~" + id_length_limit = 0 + + # Use values from tfvars + context = module.this.context +} + +output "label6f" { + value = { + id = module.label6f.id + id_full = module.label6f.id_full + } +} + +output "label6f_tags" { + value = module.label6f.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/complete/label6t.tf b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label6t.tf new file mode 100755 index 0000000..b5d9bc1 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label6t.tf @@ -0,0 +1,19 @@ +module "label6t" { + source = "../../" + + # Use values from tfvars, + # specifically: complete.auto.tfvars + context = module.this.context +} + +output "label6t" { + value = { + id = module.label6t.id + id_full = module.label6t.id_full + id_length_limit = module.this.context.id_length_limit + } +} + +output "label6t_tags" { + value = module.label6t.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/complete/label7.tf b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label7.tf new file mode 100755 index 0000000..bb365d4 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label7.tf @@ -0,0 +1,44 @@ +module "label7a" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + } +} + +module "label7" { + source = "../../" + + attributes = ["nodegroup"] + + context = module.label7a.context +} + + +output "label7" { + value = { + id = module.label7.id + name = module.label7.name + namespace = module.label7.namespace + stage = module.label7.stage + attributes = module.label7.attributes + delimiter = module.label7.delimiter + } +} + +output "label7_id" { + value = module.label7.id +} + +output "label7_attributes" { + value = module.label7.attributes +} + +output "label7_context" { + value = module.label7.context +} diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/complete/label8d.tf b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label8d.tf new file mode 100755 index 0000000..4252419 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label8d.tf @@ -0,0 +1,44 @@ +module "label8d" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8d_context" { + source = "../../" + + context = module.label8d.context +} + +output "label8d_context_id" { + value = module.label8d_context.id +} + +output "label8d_context_context" { + value = module.label8d_context.context +} + +output "label8d_context_tags" { + value = module.label8d_context.tags +} + +output "label8d_id" { + value = module.label8d.id +} + +output "label8d_context" { + value = module.label8d.context +} + +output "label8d_tags" { + value = module.label8d.tags +} diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/complete/label8dcd.tf b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label8dcd.tf new file mode 100755 index 0000000..ccdae21 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label8dcd.tf @@ -0,0 +1,24 @@ +module "label8dcd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "x" +} + +module "label8dcd_context" { + source = "../../" + + context = module.label8dcd.context +} + +output "label8dcd_context_id" { + value = module.label8dcd_context.id +} + +output "label8dcd_id" { + value = module.label8dcd.id +} diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/complete/label8dnd.tf b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label8dnd.tf new file mode 100755 index 0000000..2edb378 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label8dnd.tf @@ -0,0 +1,24 @@ +module "label8dnd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "" +} + +module "label8dnd_context" { + source = "../../" + + context = module.label8dnd.context +} + +output "label8dnd_context_id" { + value = module.label8dnd_context.id +} + +output "label8dnd_id" { + value = module.label8dnd.id +} diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/complete/label8l.tf b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label8l.tf new file mode 100755 index 0000000..7462f9e --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label8l.tf @@ -0,0 +1,46 @@ +module "label8l" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "lower" + label_value_case = "lower" + + tags = { + "kubernetes.io/cluster/" = "shared" + "upperTEST" = "testUPPER" + } +} + +module "label8l_context" { + source = "../../" + + context = module.label8l.context +} + +output "label8l_context_id" { + value = module.label8l_context.id +} + +output "label8l_context_context" { + value = module.label8l_context.context +} + +output "label8l_context_tags" { + value = module.label8l_context.tags +} + +output "label8l_id" { + value = module.label8l.id +} + +output "label8l_context" { + value = module.label8l.context +} + +output "label8l_tags" { + value = module.label8l.tags +} diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/complete/label8n.tf b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label8n.tf new file mode 100755 index 0000000..fd4ad57 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label8n.tf @@ -0,0 +1,45 @@ +module "label8n" { + source = "../../" + + enabled = true + namespace = "EG" + environment = "demo" + name = "blue" + attributes = ["eks", "ClusteR"] + delimiter = "-" + label_value_case = "none" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8n_context" { + source = "../../" + + context = module.label8n.context +} + +output "label8n_context_id" { + value = module.label8n_context.id +} + +output "label8n_context_context" { + value = module.label8n_context.context +} + +output "label8n_context_tags" { + value = module.label8n_context.tags +} + +output "label8n_id" { + value = module.label8n.id +} + +output "label8n_context" { + value = module.label8n.context +} + +output "label8n_tags" { + value = module.label8n.tags +} diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/complete/label8t.tf b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label8t.tf new file mode 100755 index 0000000..cb54c7a --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label8t.tf @@ -0,0 +1,45 @@ +module "label8t" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["EKS", "cluster"] + delimiter = "-" + label_key_case = "title" + label_value_case = "title" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8t_context" { + source = "../../" + + context = module.label8t.context +} + +output "label8t_context_id" { + value = module.label8t_context.id +} + +output "label8t_context_context" { + value = module.label8t_context.context +} + +output "label8t_context_tags" { + value = module.label8t_context.tags +} + +output "label8t_id" { + value = module.label8t.id +} + +output "label8t_context" { + value = module.label8t.context +} + +output "label8t_tags" { + value = module.label8t.tags +} diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/complete/label8u.tf b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label8u.tf new file mode 100755 index 0000000..499535b --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/complete/label8u.tf @@ -0,0 +1,50 @@ +module "label8u" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "upper" + label_value_case = "upper" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8u_context" { + source = "../../" + + context = module.label8u.context +} + +output "label8u_context_id" { + value = module.label8u_context.id +} + +output "label8u_context_context" { + value = module.label8u_context.context +} + +// debug +output "label8u_context_normalized_context" { + value = module.label8u_context.normalized_context +} + +output "label8u_context_tags" { + value = module.label8u_context.tags +} + +output "label8u_id" { + value = module.label8u.id +} + +output "label8u_context" { + value = module.label8u.context +} + +output "label8u_tags" { + value = module.label8u.tags +} diff --git a/.terraform/modules/datadog_integration.lambda_label/examples/complete/versions.tf b/.terraform/modules/datadog_integration.lambda_label/examples/complete/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/examples/complete/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration.lambda_label/exports/context.tf b/.terraform/modules/datadog_integration.lambda_label/exports/context.tf new file mode 100755 index 0000000..81f99b4 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/exports/context.tf @@ -0,0 +1,202 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration.lambda_label/main.tf b/.terraform/modules/datadog_integration.lambda_label/main.tf new file mode 100755 index 0000000..0deda2b --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/main.tf @@ -0,0 +1,146 @@ +locals { + + defaults = { + label_order = ["namespace", "environment", "stage", "name", "attributes"] + regex_replace_chars = "/[^-a-zA-Z0-9]/" + delimiter = "-" + replacement = "" + id_length_limit = 0 + id_hash_length = 5 + label_key_case = "title" + label_value_case = "lower" + } + + # So far, we have decided not to allow overriding replacement or id_hash_length + replacement = local.defaults.replacement + id_hash_length = local.defaults.id_hash_length + + # The values provided by variables supersede the values inherited from the context object, + # except for tags and attributes which are merged. + input = { + # It would be nice to use coalesce here, but we cannot, because it + # is an error for all the arguments to coalesce to be empty. + enabled = var.enabled == null ? var.context.enabled : var.enabled + namespace = var.namespace == null ? var.context.namespace : var.namespace + environment = var.environment == null ? var.context.environment : var.environment + stage = var.stage == null ? var.context.stage : var.stage + name = var.name == null ? var.context.name : var.name + delimiter = var.delimiter == null ? var.context.delimiter : var.delimiter + # modules tack on attributes (passed by var) to the end of the list (passed by context) + attributes = compact(distinct(concat(coalesce(var.context.attributes, []), coalesce(var.attributes, [])))) + tags = merge(var.context.tags, var.tags) + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + label_order = var.label_order == null ? var.context.label_order : var.label_order + regex_replace_chars = var.regex_replace_chars == null ? var.context.regex_replace_chars : var.regex_replace_chars + id_length_limit = var.id_length_limit == null ? var.context.id_length_limit : var.id_length_limit + label_key_case = var.label_key_case == null ? lookup(var.context, "label_key_case", null) : var.label_key_case + label_value_case = var.label_value_case == null ? lookup(var.context, "label_value_case", null) : var.label_value_case + } + + + enabled = local.input.enabled + regex_replace_chars = coalesce(local.input.regex_replace_chars, local.defaults.regex_replace_chars) + + # string_label_names are names of inputs that are strings (not list of strings) used as labels + string_label_names = ["name", "namespace", "environment", "stage"] + normalized_labels = { for k in local.string_label_names : k => + local.input[k] == null ? "" : replace(local.input[k], local.regex_replace_chars, local.replacement) + } + normalized_attributes = compact(distinct([for v in local.input.attributes : replace(v, local.regex_replace_chars, local.replacement)])) + + formatted_labels = { for k in local.string_label_names : k => local.label_value_case == "none" ? local.normalized_labels[k] : + local.label_value_case == "title" ? title(lower(local.normalized_labels[k])) : + local.label_value_case == "upper" ? upper(local.normalized_labels[k]) : lower(local.normalized_labels[k]) + } + + attributes = compact(distinct([ + for v in local.normalized_attributes : (local.label_value_case == "none" ? v : + local.label_value_case == "title" ? title(lower(v)) : + local.label_value_case == "upper" ? upper(v) : lower(v)) + ])) + + name = local.formatted_labels["name"] + namespace = local.formatted_labels["namespace"] + environment = local.formatted_labels["environment"] + stage = local.formatted_labels["stage"] + + delimiter = local.input.delimiter == null ? local.defaults.delimiter : local.input.delimiter + label_order = local.input.label_order == null ? local.defaults.label_order : coalescelist(local.input.label_order, local.defaults.label_order) + id_length_limit = local.input.id_length_limit == null ? local.defaults.id_length_limit : local.input.id_length_limit + label_key_case = local.input.label_key_case == null ? local.defaults.label_key_case : local.input.label_key_case + label_value_case = local.input.label_value_case == null ? local.defaults.label_value_case : local.input.label_value_case + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + + tags = merge(local.generated_tags, local.input.tags) + + tags_as_list_of_maps = flatten([ + for key in keys(local.tags) : merge( + { + key = key + value = local.tags[key] + }, var.additional_tag_map) + ]) + + tags_context = { + # For AWS we need `Name` to be disambiguated since it has a special meaning + name = local.id + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = local.id_context.attributes + } + + generated_tags = { + for l in keys(local.tags_context) : + local.label_key_case == "upper" ? upper(l) : ( + local.label_key_case == "lower" ? lower(l) : title(lower(l)) + ) => local.tags_context[l] if length(local.tags_context[l]) > 0 + } + + id_context = { + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = join(local.delimiter, local.attributes) + } + + labels = [for l in local.label_order : local.id_context[l] if length(local.id_context[l]) > 0] + + id_full = join(local.delimiter, local.labels) + # Create a truncated ID if needed + delimiter_length = length(local.delimiter) + # Calculate length of normal part of ID, leaving room for delimiter and hash + id_truncated_length_limit = local.id_length_limit - (local.id_hash_length + local.delimiter_length) + # Truncate the ID and ensure a single (not double) trailing delimiter + id_truncated = local.id_truncated_length_limit <= 0 ? "" : "${trimsuffix(substr(local.id_full, 0, local.id_truncated_length_limit), local.delimiter)}${local.delimiter}" + # Support usages that disallow numeric characters. Would prefer tr 0-9 q-z but Terraform does not support it. + id_hash_plus = "${md5(local.id_full)}qrstuvwxyz" + id_hash_case = local.label_value_case == "title" ? title(local.id_hash_plus) : local.label_value_case == "upper" ? upper(local.id_hash_plus) : local.label_value_case == "lower" ? lower(local.id_hash_plus) : local.id_hash_plus + id_hash = replace(local.id_hash_case, local.regex_replace_chars, local.replacement) + # Create the short ID by adding a hash to the end of the truncated ID + id_short = substr("${local.id_truncated}${local.id_hash}", 0, local.id_length_limit) + id = local.id_length_limit != 0 && length(local.id_full) > local.id_length_limit ? local.id_short : local.id_full + + + # Context of this label to pass to other label modules + output_context = { + enabled = local.enabled + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + delimiter = local.delimiter + attributes = local.attributes + tags = local.tags + additional_tag_map = local.additional_tag_map + label_order = local.label_order + regex_replace_chars = local.regex_replace_chars + id_length_limit = local.id_length_limit + label_key_case = local.label_key_case + label_value_case = local.label_value_case + } + +} diff --git a/.terraform/modules/datadog_integration.lambda_label/outputs.tf b/.terraform/modules/datadog_integration.lambda_label/outputs.tf new file mode 100755 index 0000000..87ad1be --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/outputs.tf @@ -0,0 +1,88 @@ +output "id" { + value = local.enabled ? local.id : "" + description = "Disambiguated ID restricted to `id_length_limit` characters in total" +} + +output "id_full" { + value = local.enabled ? local.id_full : "" + description = "Disambiguated ID not restricted in length" +} + +output "enabled" { + value = local.enabled + description = "True if module is enabled, false otherwise" +} + +output "namespace" { + value = local.enabled ? local.namespace : "" + description = "Normalized namespace" +} + +output "environment" { + value = local.enabled ? local.environment : "" + description = "Normalized environment" +} + +output "name" { + value = local.enabled ? local.name : "" + description = "Normalized name" +} + +output "stage" { + value = local.enabled ? local.stage : "" + description = "Normalized stage" +} + +output "delimiter" { + value = local.enabled ? local.delimiter : "" + description = "Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes`" +} + +output "attributes" { + value = local.enabled ? local.attributes : [] + description = "List of attributes" +} + +output "tags" { + value = local.enabled ? local.tags : {} + description = "Normalized Tag map" +} + +output "additional_tag_map" { + value = local.additional_tag_map + description = "The merged additional_tag_map" +} + +output "label_order" { + value = local.label_order + description = "The naming order actually used to create the ID" +} + +output "regex_replace_chars" { + value = local.regex_replace_chars + description = "The regex_replace_chars actually used to create the ID" +} + +output "id_length_limit" { + value = local.id_length_limit + description = "The id_length_limit actually used to create the ID, with `0` meaning unlimited" +} + +output "tags_as_list_of_maps" { + value = local.tags_as_list_of_maps + description = "Additional tags as a list of maps, which can be used in several AWS resources" +} + +output "normalized_context" { + value = local.output_context + description = "Normalized context of this module" +} + +output "context" { + value = local.input + description = <<-EOT + Merged but otherwise unmodified input to this module, to be used as context input to other modules. + Note: this version will have null values as defaults, not the values actually used as defaults. +EOT +} + diff --git a/.terraform/modules/datadog_integration.lambda_label/test/Makefile b/.terraform/modules/datadog_integration.lambda_label/test/Makefile new file mode 100755 index 0000000..ea15d62 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/test/Makefile @@ -0,0 +1,43 @@ +TEST_HARNESS ?= https://github.com/cloudposse/test-harness.git +TEST_HARNESS_BRANCH ?= master +TEST_HARNESS_PATH = $(realpath .test-harness) +BATS_ARGS ?= --tap +BATS_LOG ?= test.log + +# Define a macro to run the tests +define RUN_TESTS +@echo "Running tests in $(1)" +@cd $(1) && bats $(BATS_ARGS) $(addsuffix .bats,$(addprefix $(TEST_HARNESS_PATH)/test/terraform/,$(TESTS))) +endef + +default: all + +-include Makefile.* + +## Provision the test-harnesss +.test-harness: + [ -d $@ ] || git clone --depth=1 -b $(TEST_HARNESS_BRANCH) $(TEST_HARNESS) $@ + +## Initialize the tests +init: .test-harness + +## Install all dependencies (OS specific) +deps:: + @exit 0 + +## Clean up the test harness +clean: + [ "$(TEST_HARNESS_PATH)" == "/" ] || rm -rf $(TEST_HARNESS_PATH) + +## Run all tests +all: module examples/complete + +## Run basic sanity checks against the module itself +module: export TESTS ?= installed lint get-modules module-pinning get-plugins provider-pinning validate terraform-docs input-descriptions output-descriptions +module: deps + $(call RUN_TESTS, ../) + +## Run tests against example +examples/complete: export TESTS ?= installed lint get-modules get-plugins validate init plan apply +examples/complete: deps + $(call RUN_TESTS, ../$@) diff --git a/.terraform/modules/datadog_integration.lambda_label/test/Makefile.alpine b/.terraform/modules/datadog_integration.lambda_label/test/Makefile.alpine new file mode 100755 index 0000000..7925b18 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/test/Makefile.alpine @@ -0,0 +1,5 @@ +ifneq (,$(wildcard /sbin/apk)) +## Install all dependencies for alpine +deps:: init + @apk add --update terraform-docs@cloudposse json2hcl@cloudposse +endif diff --git a/.terraform/modules/datadog_integration.lambda_label/test/src/Makefile b/.terraform/modules/datadog_integration.lambda_label/test/src/Makefile new file mode 100755 index 0000000..b772822 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/test/src/Makefile @@ -0,0 +1,30 @@ +export TF_CLI_ARGS_init ?= -get-plugins=true +export TERRAFORM_VERSION ?= $(shell curl -s https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r -M '.current_version' | cut -d. -f1-2) + +.DEFAULT_GOAL : all +.PHONY: all + +## Default target +all: test + +.PHONY : init +## Initialize tests +init: + @exit 0 + +.PHONY : test +## Run tests +test: init + go mod download + go test -v -timeout 60m -run TestExamplesComplete + +## Run tests in docker container +docker/test: + docker run --name terratest --rm -it -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e GITHUB_TOKEN \ + -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" \ + -v $(CURDIR)/../../:/module/ cloudposse/test-harness:latest -C /module/test/src test + +.PHONY : clean +## Clean up files +clean: + rm -rf ../../examples/complete/*.tfstate* diff --git a/.terraform/modules/datadog_integration.lambda_label/test/src/examples_complete_test.go b/.terraform/modules/datadog_integration.lambda_label/test/src/examples_complete_test.go new file mode 100755 index 0000000..156e293 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/test/src/examples_complete_test.go @@ -0,0 +1,293 @@ +package test + +import ( + "fmt" + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" + "github.com/qdm12/reprint" + "github.com/stretchr/testify/assert" +) + +type NLContext struct { + AdditionalTagMap map[string]string `json:"additional_tag_map"` + Attributes []string `json:"attributes"` + Delimiter interface{} `json:"delimiter"` + Enabled bool `json:"enabled"` + Environment interface{} `json:"environment"` + LabelOrder []string `json:"label_order"` + Name interface{} `json:"name"` + Namespace interface{} `json:"namespace"` + RegexReplaceChars interface{} `json:"regex_replace_chars"` + Stage interface{} `json:"stage"` + Tags map[string]string `json:"tags"` +} + +// Test the Terraform module in examples/complete using Terratest. +func TestExamplesComplete(t *testing.T) { + t.Parallel() + + terraformOptions := &terraform.Options{ + // The path to where our Terraform code is located + TerraformDir: "../../examples/complete", + Upgrade: true, + } + + // At the end of the test, run `terraform destroy` to clean up any resources that were created + defer terraform.Destroy(t, terraformOptions) + + // This will run `terraform init` and `terraform apply` and fail the test if there are any errors + terraform.InitAndApply(t, terraformOptions) + + expectedLabel1Context := NLContext{ + Enabled: true, + Namespace: "CloudPosse", + Environment: "UAT", + Stage: "build", + Name: "Winston Churchroom", + Attributes: []string{"fire", "water", "earth", "air"}, + Delimiter: "-", + LabelOrder: []string{"name", "environment", "stage", "attributes"}, + Tags: map[string]string{ + "City": "Dublin", + "Environment": "Private", + }, + AdditionalTagMap: map[string]string{}, + } + + var expectedLabel1NormalizedContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel1NormalizedContext) + expectedLabel1NormalizedContext.Namespace = "cloudposse" + expectedLabel1NormalizedContext.Environment = "uat" + expectedLabel1NormalizedContext.Name = "winstonchurchroom" + expectedLabel1NormalizedContext.RegexReplaceChars = "/[^-a-zA-Z0-9]/" + expectedLabel1NormalizedContext.Tags = map[string]string{ + "City": "Dublin", + "Environment": "Private", + "Namespace": "cloudposse", + "Stage": "build", + "Name": "winstonchurchroom-uat-build-fire-water-earth-air", + "Attributes": "fire-water-earth-air", + } + + var label1NormalizedContext, label1Context NLContext + // Run `terraform output` to get the value of an output variable + label1 := terraform.OutputMap(t, terraformOptions, "label1") + label1Tags := terraform.OutputMap(t, terraformOptions, "label1_tags") + terraform.OutputStruct(t, terraformOptions, "label1_normalized_context", &label1NormalizedContext) + terraform.OutputStruct(t, terraformOptions, "label1_context", &label1Context) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1["id"]) + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1Tags["Name"]) + assert.Equal(t, "Dublin", label1Tags["City"]) + assert.Equal(t, "Private", label1Tags["Environment"]) + assert.Equal(t, expectedLabel1NormalizedContext, label1NormalizedContext) + assert.Equal(t, expectedLabel1Context, label1Context) + + label1t1 := terraform.OutputMap(t, terraformOptions, "label1t1") + label1t1Tags := terraform.OutputMap(t, terraformOptions, "label1t1_tags") + assert.Equal(t, "winstonchurchroom-uat-6a0b34", label1t1["id"], + "Extra hash character should be added when trailing delimiter is removed") + assert.Equal(t, label1["id"], label1t1["id_full"], "id_full should not be truncated") + assert.Equal(t, label1t1["id"], label1t1Tags["Name"], "Name tag should match ID") + + label1t2 := terraform.OutputMap(t, terraformOptions, "label1t2") + label1t2Tags := terraform.OutputMap(t, terraformOptions, "label1t2_tags") + assert.Equal(t, "winstonchurchroom-uat-b-6a0b3", label1t2["id"]) + assert.Equal(t, label1t2["id"], label1t2Tags["Name"], "Name tag should match ID") + + // Run `terraform output` to get the value of an output variable + label2 := terraform.OutputMap(t, terraformOptions, "label2") + label2Tags := terraform.OutputMap(t, terraformOptions, "label2_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2["id"]) + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2Tags["Name"]) + assert.Equal(t, "London", label2Tags["City"]) + assert.Equal(t, "Public", label2Tags["Environment"]) + + var expectedLabel3cContext, label3cContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel3cContext) + expectedLabel3cContext.Name = "Starfish" + expectedLabel3cContext.Stage = "release" + expectedLabel3cContext.Delimiter = "." + expectedLabel3cContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3cContext.Tags["Eat"] = "Carrot" + expectedLabel3cContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3c := terraform.OutputMap(t, terraformOptions, "label3c") + label3cTags := terraform.OutputMap(t, terraformOptions, "label3c_tags") + terraform.OutputStruct(t, terraformOptions, "label3c_context", &label3cContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3c["id"]) + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3cTags["Name"]) + assert.Equal(t, expectedLabel3cContext, label3cContext) + + var expectedLabel3nContext, label3nContext NLContext + _ = reprint.FromTo(&expectedLabel1NormalizedContext, &expectedLabel3nContext) + expectedLabel3nContext.Name = "Starfish" + expectedLabel3nContext.Stage = "release" + expectedLabel3nContext.Delimiter = "." + expectedLabel3nContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3nContext.Tags["Eat"] = "Carrot" + expectedLabel3nContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3n := terraform.OutputMap(t, terraformOptions, "label3n") + label3nTags := terraform.OutputMap(t, terraformOptions, "label3n_tags") + terraform.OutputStruct(t, terraformOptions, "label3n_context", &label3nContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3n["id"]) + assert.Equal(t, label1Tags["Name"], label3nTags["Name"], + "Tag from label1 normalized context should overwrite label3n generated tag") + assert.Equal(t, expectedLabel3nContext, label3nContext) + + // Run `terraform output` to get the value of an output variable + label4 := terraform.OutputMap(t, terraformOptions, "label4") + label4Tags := terraform.OutputMap(t, terraformOptions, "label4_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4["id"]) + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4Tags["Name"]) + + // Run `terraform output` to get the value of an output variable + label5 := terraform.OutputMap(t, terraformOptions, "label5") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "", label5["id"]) + + label6f := terraform.OutputMap(t, terraformOptions, "label6f") + label6fTags := terraform.OutputMap(t, terraformOptions, "label6f_tags") + // Test of setting var.label_key_case = "lower", var.label_value_case = "upper" + assert.Equal(t, "CP~UW2~PRD~NULL-LABEL", label6f["id_full"]) + assert.Equal(t, label6f["id_full"], label6f["id"], "id should not be truncated") + assert.Equal(t, label6f["id"], label6fTags["name"], "Name tag should match ID") + + label6t := terraform.OutputMap(t, terraformOptions, "label6t") + label6tTags := terraform.OutputMap(t, terraformOptions, "label6t_tags") + assert.Equal(t, "CPUW2PRDNULL-LABEL", label6t["id_full"]) + assert.NotEqual(t, label6t["id_full"], label6t["id"], "id should be truncated") + assert.Equal(t, label6t["id"], label6tTags["name"], "Name tag should match ID") + assert.Equal(t, label6t["id_length_limit"], fmt.Sprintf("%d", len(label6t["id"])), + "Truncated ID length should equal length limit") + + label7 := terraform.OutputMap(t, terraformOptions, "label7") + assert.Equal(t, "eg-demo-blue-cluster-nodegroup", label7["id"], "var.attributes should be appended after context.attributes") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter=""` returns expected value of id, context id + label8dndID := terraform.Output(t, terraformOptions, "label8dnd_id") + label8dndContextID := terraform.Output(t, terraformOptions, "label8dnd_context_id") + assert.Equal(t, "egdemobluecluster", label8dndID) + assert.Equal(t, label8dndID, label8dndContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter="x"` returns expected value of id, context id + label8dcdID := terraform.Output(t, terraformOptions, "label8dcd_id") + label8dcdContextID := terraform.Output(t, terraformOptions, "label8dcd_context_id") + assert.Equal(t, "egxdemoxbluexcluster", label8dcdID) + assert.Equal(t, label8dcdID, label8dcdContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=lower` returns expected values of id, tags, context tags + label8dExpectedTags := map[string]string{ + "Attributes": "cluster", + "Environment": "demo", + "Name": "eg-demo-blue-cluster", + "Namespace": "eg", + "kubernetes.io/cluster/": "shared", + } + + label8dID := terraform.Output(t, terraformOptions, "label8d_id") + label8dContextID := terraform.Output(t, terraformOptions, "label8d_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8dID) + assert.Equal(t, label8dID, label8dContextID, "ID and context ID should be equal") + + label8dTags := terraform.OutputMap(t, terraformOptions, "label8d_tags") + label8dContextTags := terraform.OutputMap(t, terraformOptions, "label8d_context_tags") + + assert.Exactly(t, label8dExpectedTags, label8dTags, "generated tags are different from expected") + assert.Exactly(t, label8dTags, label8dContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=lower` and `label_value_case=lower` returns expected values of id, tags, context tags + label8lExpectedTags := map[string]string{ + "attributes": "cluster", + "environment": "demo", + "name": "eg-demo-blue-cluster", + "namespace": "eg", + "kubernetes.io/cluster/": "shared", + "upperTEST": "testUPPER", + } + + label8lID := terraform.Output(t, terraformOptions, "label8l_id") + label8lContextID := terraform.Output(t, terraformOptions, "label8l_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8lID) + assert.Equal(t, label8lID, label8lContextID, "ID and context ID should be equal") + + label8lTags := terraform.OutputMap(t, terraformOptions, "label8l_tags") + label8lContextTags := terraform.OutputMap(t, terraformOptions, "label8l_context_tags") + + assert.Exactly(t, label8lExpectedTags, label8lTags, "generated tags are different from expected") + assert.Exactly(t, label8lTags, label8lContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=title` returns expected values of id, tags, context tags + label8tExpectedTags := map[string]string{ + "Attributes": "Eks-Cluster", + "Environment": "Demo", + "Name": "Eg-Demo-Blue-Eks-Cluster", + "Namespace": "Eg", + "kubernetes.io/cluster/": "shared", + } + + label8tID := terraform.Output(t, terraformOptions, "label8t_id") + label8tContextID := terraform.Output(t, terraformOptions, "label8t_context_id") + assert.Equal(t, "Eg-Demo-Blue-Eks-Cluster", label8tID) + assert.Equal(t, label8tID, label8tContextID, "ID and context ID should be equal") + + label8tTags := terraform.OutputMap(t, terraformOptions, "label8t_tags") + label8tContextTags := terraform.OutputMap(t, terraformOptions, "label8t_context_tags") + + assert.Exactly(t, label8tExpectedTags, label8tTags, "generated tags are different from expected") + assert.Exactly(t, label8tTags, label8tContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=upper` and `label_value_case=upper` returns expected values of id, tags, context tags + label8uExpectedTags := map[string]string{ + "ATTRIBUTES": "CLUSTER", + "ENVIRONMENT": "DEMO", + "NAME": "EG-DEMO-BLUE-CLUSTER", + "NAMESPACE": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8uID := terraform.Output(t, terraformOptions, "label8u_id") + label8uContextID := terraform.Output(t, terraformOptions, "label8u_context_id") + assert.Equal(t, "EG-DEMO-BLUE-CLUSTER", label8uID) + assert.Equal(t, label8uID, label8uContextID, "ID and context ID should be equal") + + label8uTags := terraform.OutputMap(t, terraformOptions, "label8u_tags") + label8uContextTags := terraform.OutputMap(t, terraformOptions, "label8u_context_tags") + + assert.Exactly(t, label8uExpectedTags, label8uTags, "generated tags are different from expected") + assert.Exactly(t, label8uTags, label8uContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=none` returns expected values of id, tags, context tags + label8nExpectedTags := map[string]string{ + "Attributes": "eks-ClusteR", + "Environment": "demo", + "Name": "EG-demo-blue-eks-ClusteR", + "Namespace": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8nID := terraform.Output(t, terraformOptions, "label8n_id") + label8nContextID := terraform.Output(t, terraformOptions, "label8n_context_id") + assert.Equal(t, "EG-demo-blue-eks-ClusteR", label8nID) + assert.Equal(t, label8nID, label8nContextID, "ID and context ID should be equal") + + label8nTags := terraform.OutputMap(t, terraformOptions, "label8n_tags") + label8nContextTags := terraform.OutputMap(t, terraformOptions, "label8n_context_tags") + + assert.Exactly(t, label8nExpectedTags, label8nTags, "generated tags are different from expected") + assert.Exactly(t, label8nTags, label8nContextTags, "tags and context tags should be equal") +} diff --git a/.terraform/modules/datadog_integration.lambda_label/test/src/go.mod b/.terraform/modules/datadog_integration.lambda_label/test/src/go.mod new file mode 100755 index 0000000..d866541 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/test/src/go.mod @@ -0,0 +1,9 @@ +module github.com/cloudposse/terraform-null-label + +go 1.14 + +require ( + github.com/gruntwork-io/terratest v0.31.1 + github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 + github.com/stretchr/testify v1.6.1 +) diff --git a/.terraform/modules/datadog_integration.lambda_label/test/src/go.sum b/.terraform/modules/datadog_integration.lambda_label/test/src/go.sum new file mode 100755 index 0000000..b8d46b1 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/test/src/go.sum @@ -0,0 +1,595 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= +github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.5/go.mod h1:foo3aIXRQ90zFve3r0QiDsrjGDUwWhKl0ZOQy1CT14k= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= +github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200109221225-a4f60165b7a3/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= +github.com/gruntwork-io/terratest v0.31.1 h1:MPGe/5pGgJAIZ/hb+0LM1KyJKSi/QyxSkHoP9/CBhJg= +github.com/gruntwork-io/terratest v0.31.1/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= +github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4= +github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= +github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= +k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= +k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= +k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= +k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= +k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= +k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= +k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= +modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/.terraform/modules/datadog_integration.lambda_label/variables.tf b/.terraform/modules/datadog_integration.lambda_label/variables.tf new file mode 100755 index 0000000..40fb268 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/variables.tf @@ -0,0 +1,157 @@ +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} diff --git a/.terraform/modules/datadog_integration.lambda_label/versions.tf b/.terraform/modules/datadog_integration.lambda_label/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration.lambda_label/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration.this/LICENSE b/.terraform/modules/datadog_integration.this/LICENSE new file mode 100755 index 0000000..c844c70 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017-2020 Cloud Posse, LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/.terraform/modules/datadog_integration.this/Makefile b/.terraform/modules/datadog_integration.this/Makefile new file mode 100755 index 0000000..97d8087 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/Makefile @@ -0,0 +1,10 @@ +SHELL := /bin/bash + +# List of targets the `readme` target should call before generating the readme +export README_DEPS ?= docs/targets.md docs/terraform.md + +-include $(shell curl -sSL -o .build-harness "https://git.io/build-harness"; echo .build-harness) + +## Lint terraform code +lint: + $(SELF) terraform/install terraform/get-modules terraform/get-plugins terraform/lint terraform/validate diff --git a/.terraform/modules/datadog_integration.this/README.md b/.terraform/modules/datadog_integration.this/README.md new file mode 100755 index 0000000..32950e4 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/README.md @@ -0,0 +1,938 @@ + +# terraform-null-label [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-null-label.svg)](https://github.com/cloudposse/terraform-null-label/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) + + +[![README Header][readme_header_img]][readme_header_link] + +[![Cloud Posse][logo]](https://cpco.io/homepage) + + + +Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + +This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. +However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). +So if you prefer the term `stage` to `environment` +you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. +- If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. +- If you want the attributes in a different order, you can specify that, too, with the `label_order` list. +- You can set a maximum length for the name, and the module will create a unique name that fits within that length. +- You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. +- The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + +It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. +For example, if you have 10 instances, there should be 10 different labels. +However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + +All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + +**NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. +With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + +- Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. +- Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. +- Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. + + +--- + +This project is part of our comprehensive ["SweetOps"](https://cpco.io/sweetops) approach towards DevOps. +[][share_email] +[][share_googleplus] +[][share_facebook] +[][share_reddit] +[][share_linkedin] +[][share_twitter] + + +[![Terraform Open Source Modules](https://docs.cloudposse.com/images/terraform-open-source-modules.svg)][terraform_modules] + + + +It's 100% Open Source and licensed under the [APACHE2](LICENSE). + + + + + + + +We literally have [*hundreds of terraform modules*][terraform_modules] that are Open Source and well-maintained. Check them out! + + + + + + + +## Security & Compliance [](https://bridgecrew.io/) + +Security scanning is graciously provided by Bridgecrew. Bridgecrew is the leading fully hosted, cloud-native solution providing continuous Terraform security and compliance. + +| Benchmark | Description | +|--------|---------------| +| [![Infrastructure Security](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/general)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=INFRASTRUCTURE+SECURITY) | Infrastructure Security Compliance | +| [![CIS KUBERNETES](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_kubernetes)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+KUBERNETES+V1.5) | Center for Internet Security, KUBERNETES Compliance | +| [![CIS AWS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_aws)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AWS+V1.2) | Center for Internet Security, AWS Compliance | +| [![CIS AZURE](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_azure)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AZURE+V1.1) | Center for Internet Security, AZURE Compliance | +| [![PCI-DSS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/pci)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=PCI-DSS+V3.2) | Payment Card Industry Data Security Standards Compliance | +| [![NIST-800-53](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/nist)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=NIST-800-53) | National Institute of Standards and Technology Compliance | +| [![ISO27001](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/iso)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=ISO27001) | Information Security Management System, ISO/IEC 27001 Compliance | +| [![SOC2](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/soc2)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=SOC2)| Service Organization Control 2 Compliance | +| [![CIS GCP](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_gcp)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+GCP+V1.1) | Center for Internet Security, GCP Compliance | +| [![HIPAA](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/hipaa)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=HIPAA) | Health Insurance Portability and Accountability Compliance | + + + +## Usage + + +**IMPORTANT:** We do not pin modules to versions in our examples because of the +difficulty of keeping the versions in the documentation in sync with the latest released versions. +We highly recommend that in your code you pin the version to the exact version you are +using so that your infrastructure remains stable, and update versions in a +systematic way so that they do not catch you by surprise. + +Also, because of a bug in the Terraform registry ([hashicorp/terraform#21417](https://github.com/hashicorp/terraform/issues/21417)), +the registry shows many of our inputs as required when in fact they are optional. +The table below correctly indicates which inputs are required. + + +### Defaults + +Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. +The context object is a single object that contains all the input values for `terraform-null-label`. +However, each input value can also be specified individually by name as a standard Terraform variable, +and the value of those variables, when set to something other than `null`, will override the value +in the context object. In order to allow chaining of these objects, where the context object input to one +module is transformed and passed to the next module, all the variables default to `null` or empty collections. +The actual default values used when nothing is explicitly set are describe in the documentation below. + +For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, +`terraform-null-label` will actually use the default delimiter `-` (hyphen). + +A non-obvious but intentional consequence of this design is that once a module sets a non-default value, +future modules in the chain cannot reset the value back to the original default. Insted, the new setting +becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, +so once a tag is added, it will remain in the tag set and cannot be removed, although its value can +be overwritten. + +### Simple Example + +```hcl +module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} +``` + +This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` +(you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + +Now reference the label when creating an instance: + +```hcl +resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags +} +``` + +Or define a security group: + +```hcl +resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} +``` + + +### Advanced Example + +Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + +```hcl +module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] +} + +module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] +} +``` + +
+ +### Advanced Example 2 + +Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + +```hcl +tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } +] +``` + +Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + +```hcl +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} +``` + +
+ +### Advanced Example 3 + +See [complete example](./examples/complete) for even more examples. + +This example shows how you can pass the `context` output of one label module to the next label_module, +allowing you to create one label that has the base set of values, and then creating every extra label +as a derivative of that. + +
Click to show + +```hcl +module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} +``` + +This creates label outputs like this: + +```hcl +label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" +} +label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } +} +label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } +} +label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" +} +label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" +} +label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } +} +label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" +} +label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, +] +label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" +} +label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } +} +label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } +} +label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" +} + +``` + +
+ + + + + + + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + + + + +## Share the Love + +Like this project? Please give it a ★ on [our GitHub](https://github.com/cloudposse/terraform-null-label)! (it helps us **a lot**) + +Are you using this project or any of our other projects? Consider [leaving a testimonial][testimonial]. =) + + +## Related Projects + +Check out these related projects. + +- [terraform-terraform-label](https://github.com/cloudposse/terraform-terraform-label) - Terraform Module to define a consistent naming convention by (namespace, environment, stage, name, [attributes]) + + + +## Help + +**Got a question?** We got answers. + +File a GitHub [issue](https://github.com/cloudposse/terraform-null-label/issues), send us an [email][email] or join our [Slack Community][slack]. + +[![README Commercial Support][readme_commercial_support_img]][readme_commercial_support_link] + +## DevOps Accelerator for Startups + + +We are a [**DevOps Accelerator**][commercial_support]. We'll help you build your cloud infrastructure from the ground up so you can own it. Then we'll show you how to operate it and stick around for as long as you need us. + +[![Learn More](https://img.shields.io/badge/learn%20more-success.svg?style=for-the-badge)][commercial_support] + +Work directly with our team of DevOps experts via email, slack, and video conferencing. + +We deliver 10x the value for a fraction of the cost of a full-time engineer. Our track record is not even funny. If you want things done right and you need it done FAST, then we're your best bet. + +- **Reference Architecture.** You'll get everything you need from the ground up built using 100% infrastructure as code. +- **Release Engineering.** You'll have end-to-end CI/CD with unlimited staging environments. +- **Site Reliability Engineering.** You'll have total visibility into your apps and microservices. +- **Security Baseline.** You'll have built-in governance with accountability and audit logs for all changes. +- **GitOps.** You'll be able to operate your infrastructure via Pull Requests. +- **Training.** You'll receive hands-on training so your team can operate what we build. +- **Questions.** You'll have a direct line of communication between our teams via a Shared Slack channel. +- **Troubleshooting.** You'll get help to triage when things aren't working. +- **Code Reviews.** You'll receive constructive feedback on Pull Requests. +- **Bug Fixes.** We'll rapidly work with you to fix any bugs in our projects. + +## Slack Community + +Join our [Open Source Community][slack] on Slack. It's **FREE** for everyone! Our "SweetOps" community is where you get to talk with others who share a similar vision for how to rollout and manage infrastructure. This is the best place to talk shop, ask questions, solicit feedback, and work together as a community to build totally *sweet* infrastructure. + +## Discourse Forums + +Participate in our [Discourse Forums][discourse]. Here you'll find answers to commonly asked questions. Most questions will be related to the enormous number of projects we support on our GitHub. Come here to collaborate on answers, find solutions, and get ideas about the products and services we value. It only takes a minute to get started! Just sign in with SSO using your GitHub account. + +## Newsletter + +Sign up for [our newsletter][newsletter] that covers everything on our technology radar. Receive updates on what we're up to on GitHub as well as awesome new projects we discover. + +## Office Hours + +[Join us every Wednesday via Zoom][office_hours] for our weekly "Lunch & Learn" sessions. It's **FREE** for everyone! + +[![zoom](https://img.cloudposse.com/fit-in/200x200/https://cloudposse.com/wp-content/uploads/2019/08/Powered-by-Zoom.png")][office_hours] + +## Contributing + +### Bug Reports & Feature Requests + +Please use the [issue tracker](https://github.com/cloudposse/terraform-null-label/issues) to report any bugs or file feature requests. + +### Developing + +If you are interested in being a contributor and want to get involved in developing this project or [help out](https://cpco.io/help-out) with our other projects, we would love to hear from you! Shoot us an [email][email]. + +In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. + + 1. **Fork** the repo on GitHub + 2. **Clone** the project to your own machine + 3. **Commit** changes to your own branch + 4. **Push** your work back up to your fork + 5. Submit a **Pull Request** so that we can review your changes + +**NOTE:** Be sure to merge the latest changes from "upstream" before making a pull request! + + +## Copyright + +Copyright © 2017-2021 [Cloud Posse, LLC](https://cpco.io/copyright) + + + +## License + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +See [LICENSE](LICENSE) for full details. + +```text +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +``` + + + + + + + + + +## Trademarks + +All other trademarks referenced herein are the property of their respective owners. + +## About + +This project is maintained and funded by [Cloud Posse, LLC][website]. Like it? Please let us know by [leaving a testimonial][testimonial]! + +[![Cloud Posse][logo]][website] + +We're a [DevOps Professional Services][hire] company based in Los Angeles, CA. We ❤️ [Open Source Software][we_love_open_source]. + +We offer [paid support][commercial_support] on all of our projects. + +Check out [our other projects][github], [follow us on twitter][twitter], [apply for a job][jobs], or [hire us][hire] to help with your cloud strategy and implementation. + + + +### Contributors + + +| [![Erik Osterman][osterman_avatar]][osterman_homepage]
[Erik Osterman][osterman_homepage] | [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]
[Andriy Knysh][aknysh_homepage] | [![Igor Rodionov][goruha_avatar]][goruha_homepage]
[Igor Rodionov][goruha_homepage] | [![Sergey Vasilyev][s2504s_avatar]][s2504s_homepage]
[Sergey Vasilyev][s2504s_homepage] | [![Michael Pereira][MichaelPereira_avatar]][MichaelPereira_homepage]
[Michael Pereira][MichaelPereira_homepage] | [![Jamie Nelson][Jamie-BitFlight_avatar]][Jamie-BitFlight_homepage]
[Jamie Nelson][Jamie-BitFlight_homepage] | [![Vladimir][SweetOps_avatar]][SweetOps_homepage]
[Vladimir][SweetOps_homepage] | [![Daren Desjardins][darend_avatar]][darend_homepage]
[Daren Desjardins][darend_homepage] | [![Maarten van der Hoef][maartenvanderhoef_avatar]][maartenvanderhoef_homepage]
[Maarten van der Hoef][maartenvanderhoef_homepage] | [![Adam Tibbing][tibbing_avatar]][tibbing_homepage]
[Adam Tibbing][tibbing_homepage] | +|---|---|---|---|---|---|---|---|---|---| + + + [osterman_homepage]: https://github.com/osterman + [osterman_avatar]: https://img.cloudposse.com/150x150/https://github.com/osterman.png + [aknysh_homepage]: https://github.com/aknysh + [aknysh_avatar]: https://img.cloudposse.com/150x150/https://github.com/aknysh.png + [goruha_homepage]: https://github.com/goruha + [goruha_avatar]: https://img.cloudposse.com/150x150/https://github.com/goruha.png + [s2504s_homepage]: https://github.com/s2504s + [s2504s_avatar]: https://img.cloudposse.com/150x150/https://github.com/s2504s.png + [MichaelPereira_homepage]: https://github.com/MichaelPereira + [MichaelPereira_avatar]: https://img.cloudposse.com/150x150/https://github.com/MichaelPereira.png + [Jamie-BitFlight_homepage]: https://github.com/Jamie-BitFlight + [Jamie-BitFlight_avatar]: https://img.cloudposse.com/150x150/https://github.com/Jamie-BitFlight.png + [SweetOps_homepage]: https://github.com/SweetOps + [SweetOps_avatar]: https://img.cloudposse.com/150x150/https://github.com/SweetOps.png + [darend_homepage]: https://github.com/darend + [darend_avatar]: https://img.cloudposse.com/150x150/https://github.com/darend.png + [maartenvanderhoef_homepage]: https://github.com/maartenvanderhoef + [maartenvanderhoef_avatar]: https://img.cloudposse.com/150x150/https://github.com/maartenvanderhoef.png + [tibbing_homepage]: https://github.com/tibbing + [tibbing_avatar]: https://img.cloudposse.com/150x150/https://github.com/tibbing.png + +[![README Footer][readme_footer_img]][readme_footer_link] +[![Beacon][beacon]][website] + + [logo]: https://cloudposse.com/logo-300x69.svg + [docs]: https://cpco.io/docs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=docs + [website]: https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=website + [github]: https://cpco.io/github?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=github + [jobs]: https://cpco.io/jobs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=jobs + [hire]: https://cpco.io/hire?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=hire + [slack]: https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=slack + [linkedin]: https://cpco.io/linkedin?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=linkedin + [twitter]: https://cpco.io/twitter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=twitter + [testimonial]: https://cpco.io/leave-testimonial?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=testimonial + [office_hours]: https://cloudposse.com/office-hours?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=office_hours + [newsletter]: https://cpco.io/newsletter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=newsletter + [discourse]: https://ask.sweetops.com/?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=discourse + [email]: https://cpco.io/email?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=email + [commercial_support]: https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=commercial_support + [we_love_open_source]: https://cpco.io/we-love-open-source?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=we_love_open_source + [terraform_modules]: https://cpco.io/terraform-modules?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=terraform_modules + [readme_header_img]: https://cloudposse.com/readme/header/img + [readme_header_link]: https://cloudposse.com/readme/header/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_header_link + [readme_footer_img]: https://cloudposse.com/readme/footer/img + [readme_footer_link]: https://cloudposse.com/readme/footer/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_footer_link + [readme_commercial_support_img]: https://cloudposse.com/readme/commercial-support/img + [readme_commercial_support_link]: https://cloudposse.com/readme/commercial-support/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_commercial_support_link + [share_twitter]: https://twitter.com/intent/tweet/?text=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_linkedin]: https://www.linkedin.com/shareArticle?mini=true&title=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_reddit]: https://reddit.com/submit/?url=https://github.com/cloudposse/terraform-null-label + [share_facebook]: https://facebook.com/sharer/sharer.php?u=https://github.com/cloudposse/terraform-null-label + [share_googleplus]: https://plus.google.com/share?url=https://github.com/cloudposse/terraform-null-label + [share_email]: mailto:?subject=terraform-null-label&body=https://github.com/cloudposse/terraform-null-label + [beacon]: https://ga-beacon.cloudposse.com/UA-76589703-4/cloudposse/terraform-null-label?pixel&cs=github&cm=readme&an=terraform-null-label diff --git a/.terraform/modules/datadog_integration.this/README.yaml b/.terraform/modules/datadog_integration.this/README.yaml new file mode 100755 index 0000000..42bdb84 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/README.yaml @@ -0,0 +1,618 @@ +name: terraform-null-label +tags: +- aws +- terraform +- terraform-modules +- naming-convention +- name +- namespace +- stage +categories: +- terraform-modules/supported +license: APACHE2 +github_repo: cloudposse/terraform-null-label +badges: +- name: Latest Release + image: https://img.shields.io/github/release/cloudposse/terraform-null-label.svg + url: https://github.com/cloudposse/terraform-null-label/releases/latest +- name: Slack Community + image: https://slack.cloudposse.com/badge.svg + url: https://slack.cloudposse.com +related: +- name: terraform-terraform-label + description: Terraform Module to define a consistent naming convention by (namespace, + environment, stage, name, [attributes]) + url: https://github.com/cloudposse/terraform-terraform-label +description: |- + Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + + This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. + However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). + So if you prefer the term `stage` to `environment` + you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. + - If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. + - If you want the attributes in a different order, you can specify that, too, with the `label_order` list. + - You can set a maximum length for the name, and the module will create a unique name that fits within that length. + - You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. + - The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + + It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. + For example, if you have 10 instances, there should be 10 different labels. + However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + + All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + + **NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. + With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + + - Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. + - Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. + - Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. +usage: |- + ### Defaults + + Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. + The context object is a single object that contains all the input values for `terraform-null-label`. + However, each input value can also be specified individually by name as a standard Terraform variable, + and the value of those variables, when set to something other than `null`, will override the value + in the context object. In order to allow chaining of these objects, where the context object input to one + module is transformed and passed to the next module, all the variables default to `null` or empty collections. + The actual default values used when nothing is explicitly set are describe in the documentation below. + + For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, + `terraform-null-label` will actually use the default delimiter `-` (hyphen). + + A non-obvious but intentional consequence of this design is that once a module sets a non-default value, + future modules in the chain cannot reset the value back to the original default. Insted, the new setting + becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, + so once a tag is added, it will remain in the tag set and cannot be removed, although its value can + be overwritten. + + ### Simple Example + + ```hcl + module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + ``` + + This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` + (you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + + Now reference the label when creating an instance: + + ```hcl + resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags + } + ``` + + Or define a security group: + + ```hcl + resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + } + ``` + + + ### Advanced Example + + Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + + ```hcl + module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] + } + + module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] + } + ``` + +
+ + ### Advanced Example 2 + + Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + + ```hcl + tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } + ] + ``` + + Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + + ```hcl + ################################ + # terraform-null-label example # + ################################ + module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } + } + + ####################### + # Launch template # + ####################### + resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } + } + + ###################### + # Autoscaling group # + ###################### + resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps + } + ``` + +
+ + ### Advanced Example 3 + + See [complete example](./examples/complete) for even more examples. + + This example shows how you can pass the `context` output of one label module to the next label_module, + allowing you to create one label that has the base set of values, and then creating every extra label + as a derivative of that. + +
Click to show + + ```hcl + module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } + } + + module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } + } + + module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } + } + ``` + + This creates label outputs like this: + + ```hcl + label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" + } + label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } + } + label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + } + label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" + } + label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } + } + label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" + } + label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, + ] + label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" + } + label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } + } + label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + } + label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + + ``` + +
+ +include: +- docs/targets.md +- docs/terraform.md +contributors: +- name: Erik Osterman + github: osterman +- name: Andriy Knysh + github: aknysh +- name: Igor Rodionov + github: goruha +- name: Sergey Vasilyev + github: s2504s +- name: Michael Pereira + github: MichaelPereira +- name: Jamie Nelson + github: Jamie-BitFlight +- name: Vladimir + github: SweetOps +- name: Daren Desjardins + github: darend +- name: Maarten van der Hoef + github: maartenvanderhoef +- name: Adam Tibbing + github: tibbing diff --git a/.terraform/modules/datadog_integration.this/docs/targets.md b/.terraform/modules/datadog_integration.this/docs/targets.md new file mode 100755 index 0000000..3dce8b3 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/docs/targets.md @@ -0,0 +1,12 @@ + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + diff --git a/.terraform/modules/datadog_integration.this/docs/terraform.md b/.terraform/modules/datadog_integration.this/docs/terraform.md new file mode 100755 index 0000000..d4f48f4 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/docs/terraform.md @@ -0,0 +1,54 @@ + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + diff --git a/.terraform/modules/datadog_integration.this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars b/.terraform/modules/datadog_integration.this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars new file mode 100755 index 0000000..f7c725f --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars @@ -0,0 +1,12 @@ +namespace = "eg" +stage = "prod" +name = "app" + +tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" +} + +additional_tag_map = { + propagate_at_launch = "true" +} diff --git a/.terraform/modules/datadog_integration.this/examples/autoscalinggroup/context.tf b/.terraform/modules/datadog_integration.this/examples/autoscalinggroup/context.tf new file mode 100755 index 0000000..b97f05f --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/autoscalinggroup/context.tf @@ -0,0 +1,216 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration.this/examples/autoscalinggroup/main.tf b/.terraform/modules/datadog_integration.this/examples/autoscalinggroup/main.tf new file mode 100755 index 0000000..f0d3aa6 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/autoscalinggroup/main.tf @@ -0,0 +1,104 @@ +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + + context = module.this.context +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template { + id = aws_launch_template.default.id + version = "$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} + +################################ +# Provider # +################################ +provider "aws" { + region = "eu-west-1" + + # Make it faster by skipping unneeded checks here + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +############################################################## +# Data sources to get VPC, subnets and security group details +############################################################## +data "aws_vpc" "default" { + default = true +} + +data "aws_subnet_ids" "all" { + vpc_id = data.aws_vpc.default.id +} + +data "aws_security_group" "default" { + vpc_id = data.aws_vpc.default.id + name = "default" +} + +data "aws_ami" "amazon_linux" { + most_recent = true + + owners = ["amazon"] + + filter { + name = "name" + + values = [ + "amzn-ami-hvm-*-x86_64-gp2", + ] + } + + filter { + name = "owner-alias" + + values = [ + "amazon", + ] + } +} + diff --git a/.terraform/modules/datadog_integration.this/examples/autoscalinggroup/outputs.tf b/.terraform/modules/datadog_integration.this/examples/autoscalinggroup/outputs.tf new file mode 100755 index 0000000..f8fcce5 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/autoscalinggroup/outputs.tf @@ -0,0 +1,12 @@ +# terraform-null-label example used here: Output list of tags applied in each format +output "tags_as_list_of_maps" { + value = module.label.tags_as_list_of_maps +} + +output "tags" { + value = module.label.tags +} + +output "id" { + value = module.label.id +} diff --git a/.terraform/modules/datadog_integration.this/examples/autoscalinggroup/versions.tf b/.terraform/modules/datadog_integration.this/examples/autoscalinggroup/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/autoscalinggroup/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration.this/examples/complete/complete.auto.tfvars b/.terraform/modules/datadog_integration.this/examples/complete/complete.auto.tfvars new file mode 100755 index 0000000..e7bc519 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/complete/complete.auto.tfvars @@ -0,0 +1,10 @@ +namespace = "cp" +environment = "uw2" +stage = "prd" +name = "null-label" + +delimiter = "" +id_length_limit = 6 + +label_key_case = "lower" +label_value_case = "upper" diff --git a/.terraform/modules/datadog_integration.this/examples/complete/context.tf b/.terraform/modules/datadog_integration.this/examples/complete/context.tf new file mode 100755 index 0000000..973d4dc --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/complete/context.tf @@ -0,0 +1,217 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration.this/examples/complete/label1.tf b/.terraform/modules/datadog_integration.this/examples/complete/label1.tf new file mode 100755 index 0000000..8da353b --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/complete/label1.tf @@ -0,0 +1,42 @@ +module "label1" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label1" { + value = { + id = module.label1.id + name = module.label1.name + namespace = module.label1.namespace + stage = module.label1.stage + attributes = module.label1.attributes + delimiter = module.label1.delimiter + } +} + +output "label1_tags" { + value = module.label1.tags +} + +output "label1_context" { + value = module.label1.context +} + +output "label1_normalized_context" { + value = module.label1.normalized_context +} + + + diff --git a/.terraform/modules/datadog_integration.this/examples/complete/label1t1.tf b/.terraform/modules/datadog_integration.this/examples/complete/label1t1.tf new file mode 100755 index 0000000..2bcb362 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/complete/label1t1.tf @@ -0,0 +1,18 @@ +module "label1t1" { + source = "../../" + + id_length_limit = 28 + + context = module.label1.context +} + +output "label1t1" { + value = { + id = module.label1t1.id + id_full = module.label1t1.id_full + } +} + +output "label1t1_tags" { + value = module.label1t1.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration.this/examples/complete/label1t2.tf b/.terraform/modules/datadog_integration.this/examples/complete/label1t2.tf new file mode 100755 index 0000000..5df651e --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/complete/label1t2.tf @@ -0,0 +1,18 @@ +module "label1t2" { + source = "../../" + + id_length_limit = 29 + + context = module.label1.context +} + +output "label1t2" { + value = { + id = module.label1t2.id + id_full = module.label1t2.id_full + } +} + +output "label1t2_tags" { + value = module.label1t2.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration.this/examples/complete/label2.tf b/.terraform/modules/datadog_integration.this/examples/complete/label2.tf new file mode 100755 index 0000000..faf7450 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/complete/label2.tf @@ -0,0 +1,42 @@ +module "label2" { + source = "../../" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + regex_replace_chars = "/[^a-zA-Z0-9-+]/" + + additional_tag_map = { + propagate_at_launch = "true" + additional_tag = "yes" + } + + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +output "label2" { + value = { + id = module.label2.id + name = module.label2.name + namespace = module.label2.namespace + stage = module.label2.stage + attributes = module.label2.attributes + delimiter = module.label2.delimiter + } +} + +output "label2_tags" { + value = module.label2.tags +} + +output "label2_tags_as_list_of_maps" { + value = module.label2.tags_as_list_of_maps +} + +output "label2_context" { + value = module.label2.context +} diff --git a/.terraform/modules/datadog_integration.this/examples/complete/label3c.tf b/.terraform/modules/datadog_integration.this/examples/complete/label3c.tf new file mode 100755 index 0000000..338a636 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/complete/label3c.tf @@ -0,0 +1,36 @@ +module "label3c" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3c" { + value = { + id = module.label3c.id + name = module.label3c.name + namespace = module.label3c.namespace + stage = module.label3c.stage + attributes = module.label3c.attributes + delimiter = module.label3c.delimiter + } +} + +output "label3c_tags" { + value = module.label3c.tags +} + +output "label3c_context" { + value = module.label3c.context +} + +output "label3c_normalized_context" { + value = module.label3c.normalized_context +} diff --git a/.terraform/modules/datadog_integration.this/examples/complete/label3n.tf b/.terraform/modules/datadog_integration.this/examples/complete/label3n.tf new file mode 100755 index 0000000..ca51282 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/complete/label3n.tf @@ -0,0 +1,36 @@ +module "label3n" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.normalized_context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3n" { + value = { + id = module.label3n.id + name = module.label3n.name + namespace = module.label3n.namespace + stage = module.label3n.stage + attributes = module.label3n.attributes + delimiter = module.label3n.delimiter + } +} + +output "label3n_tags" { + value = module.label3n.tags +} + +output "label3n_context" { + value = module.label3n.context +} + +output "label3n_normalized_context" { + value = module.label3n.normalized_context +} diff --git a/.terraform/modules/datadog_integration.this/examples/complete/label4.tf b/.terraform/modules/datadog_integration.this/examples/complete/label4.tf new file mode 100755 index 0000000..74e3ca1 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/complete/label4.tf @@ -0,0 +1,34 @@ +module "label4" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + name = "Example Cluster" + attributes = ["big", "fat", "honking", "cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label4" { + value = { + id = module.label4.id + name = module.label4.name + namespace = module.label4.namespace + stage = module.label4.stage + attributes = module.label4.attributes + delimiter = module.label4.delimiter + } +} + +output "label4_tags" { + value = module.label4.tags +} + +output "label4_context" { + value = module.label4.context +} diff --git a/.terraform/modules/datadog_integration.this/examples/complete/label5.tf b/.terraform/modules/datadog_integration.this/examples/complete/label5.tf new file mode 100755 index 0000000..0f0a76e --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/complete/label5.tf @@ -0,0 +1,33 @@ +module "label5" { + source = "../../" + enabled = false + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + } +} + +output "label5" { + value = { + id = module.label5.id + name = module.label5.name + namespace = module.label5.namespace + stage = module.label5.stage + attributes = module.label5.attributes + delimiter = module.label5.delimiter + } +} + +output "label5_tags" { + value = module.label5.tags +} + +output "label5_context" { + value = module.label5.context +} diff --git a/.terraform/modules/datadog_integration.this/examples/complete/label6f.tf b/.terraform/modules/datadog_integration.this/examples/complete/label6f.tf new file mode 100755 index 0000000..1ce1bab --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/complete/label6f.tf @@ -0,0 +1,20 @@ +module "label6f" { + source = "../../" + + delimiter = "~" + id_length_limit = 0 + + # Use values from tfvars + context = module.this.context +} + +output "label6f" { + value = { + id = module.label6f.id + id_full = module.label6f.id_full + } +} + +output "label6f_tags" { + value = module.label6f.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration.this/examples/complete/label6t.tf b/.terraform/modules/datadog_integration.this/examples/complete/label6t.tf new file mode 100755 index 0000000..b5d9bc1 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/complete/label6t.tf @@ -0,0 +1,19 @@ +module "label6t" { + source = "../../" + + # Use values from tfvars, + # specifically: complete.auto.tfvars + context = module.this.context +} + +output "label6t" { + value = { + id = module.label6t.id + id_full = module.label6t.id_full + id_length_limit = module.this.context.id_length_limit + } +} + +output "label6t_tags" { + value = module.label6t.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration.this/examples/complete/label7.tf b/.terraform/modules/datadog_integration.this/examples/complete/label7.tf new file mode 100755 index 0000000..bb365d4 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/complete/label7.tf @@ -0,0 +1,44 @@ +module "label7a" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + } +} + +module "label7" { + source = "../../" + + attributes = ["nodegroup"] + + context = module.label7a.context +} + + +output "label7" { + value = { + id = module.label7.id + name = module.label7.name + namespace = module.label7.namespace + stage = module.label7.stage + attributes = module.label7.attributes + delimiter = module.label7.delimiter + } +} + +output "label7_id" { + value = module.label7.id +} + +output "label7_attributes" { + value = module.label7.attributes +} + +output "label7_context" { + value = module.label7.context +} diff --git a/.terraform/modules/datadog_integration.this/examples/complete/label8d.tf b/.terraform/modules/datadog_integration.this/examples/complete/label8d.tf new file mode 100755 index 0000000..4252419 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/complete/label8d.tf @@ -0,0 +1,44 @@ +module "label8d" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8d_context" { + source = "../../" + + context = module.label8d.context +} + +output "label8d_context_id" { + value = module.label8d_context.id +} + +output "label8d_context_context" { + value = module.label8d_context.context +} + +output "label8d_context_tags" { + value = module.label8d_context.tags +} + +output "label8d_id" { + value = module.label8d.id +} + +output "label8d_context" { + value = module.label8d.context +} + +output "label8d_tags" { + value = module.label8d.tags +} diff --git a/.terraform/modules/datadog_integration.this/examples/complete/label8dcd.tf b/.terraform/modules/datadog_integration.this/examples/complete/label8dcd.tf new file mode 100755 index 0000000..ccdae21 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/complete/label8dcd.tf @@ -0,0 +1,24 @@ +module "label8dcd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "x" +} + +module "label8dcd_context" { + source = "../../" + + context = module.label8dcd.context +} + +output "label8dcd_context_id" { + value = module.label8dcd_context.id +} + +output "label8dcd_id" { + value = module.label8dcd.id +} diff --git a/.terraform/modules/datadog_integration.this/examples/complete/label8dnd.tf b/.terraform/modules/datadog_integration.this/examples/complete/label8dnd.tf new file mode 100755 index 0000000..2edb378 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/complete/label8dnd.tf @@ -0,0 +1,24 @@ +module "label8dnd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "" +} + +module "label8dnd_context" { + source = "../../" + + context = module.label8dnd.context +} + +output "label8dnd_context_id" { + value = module.label8dnd_context.id +} + +output "label8dnd_id" { + value = module.label8dnd.id +} diff --git a/.terraform/modules/datadog_integration.this/examples/complete/label8l.tf b/.terraform/modules/datadog_integration.this/examples/complete/label8l.tf new file mode 100755 index 0000000..7462f9e --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/complete/label8l.tf @@ -0,0 +1,46 @@ +module "label8l" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "lower" + label_value_case = "lower" + + tags = { + "kubernetes.io/cluster/" = "shared" + "upperTEST" = "testUPPER" + } +} + +module "label8l_context" { + source = "../../" + + context = module.label8l.context +} + +output "label8l_context_id" { + value = module.label8l_context.id +} + +output "label8l_context_context" { + value = module.label8l_context.context +} + +output "label8l_context_tags" { + value = module.label8l_context.tags +} + +output "label8l_id" { + value = module.label8l.id +} + +output "label8l_context" { + value = module.label8l.context +} + +output "label8l_tags" { + value = module.label8l.tags +} diff --git a/.terraform/modules/datadog_integration.this/examples/complete/label8n.tf b/.terraform/modules/datadog_integration.this/examples/complete/label8n.tf new file mode 100755 index 0000000..fd4ad57 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/complete/label8n.tf @@ -0,0 +1,45 @@ +module "label8n" { + source = "../../" + + enabled = true + namespace = "EG" + environment = "demo" + name = "blue" + attributes = ["eks", "ClusteR"] + delimiter = "-" + label_value_case = "none" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8n_context" { + source = "../../" + + context = module.label8n.context +} + +output "label8n_context_id" { + value = module.label8n_context.id +} + +output "label8n_context_context" { + value = module.label8n_context.context +} + +output "label8n_context_tags" { + value = module.label8n_context.tags +} + +output "label8n_id" { + value = module.label8n.id +} + +output "label8n_context" { + value = module.label8n.context +} + +output "label8n_tags" { + value = module.label8n.tags +} diff --git a/.terraform/modules/datadog_integration.this/examples/complete/label8t.tf b/.terraform/modules/datadog_integration.this/examples/complete/label8t.tf new file mode 100755 index 0000000..cb54c7a --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/complete/label8t.tf @@ -0,0 +1,45 @@ +module "label8t" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["EKS", "cluster"] + delimiter = "-" + label_key_case = "title" + label_value_case = "title" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8t_context" { + source = "../../" + + context = module.label8t.context +} + +output "label8t_context_id" { + value = module.label8t_context.id +} + +output "label8t_context_context" { + value = module.label8t_context.context +} + +output "label8t_context_tags" { + value = module.label8t_context.tags +} + +output "label8t_id" { + value = module.label8t.id +} + +output "label8t_context" { + value = module.label8t.context +} + +output "label8t_tags" { + value = module.label8t.tags +} diff --git a/.terraform/modules/datadog_integration.this/examples/complete/label8u.tf b/.terraform/modules/datadog_integration.this/examples/complete/label8u.tf new file mode 100755 index 0000000..499535b --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/complete/label8u.tf @@ -0,0 +1,50 @@ +module "label8u" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "upper" + label_value_case = "upper" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8u_context" { + source = "../../" + + context = module.label8u.context +} + +output "label8u_context_id" { + value = module.label8u_context.id +} + +output "label8u_context_context" { + value = module.label8u_context.context +} + +// debug +output "label8u_context_normalized_context" { + value = module.label8u_context.normalized_context +} + +output "label8u_context_tags" { + value = module.label8u_context.tags +} + +output "label8u_id" { + value = module.label8u.id +} + +output "label8u_context" { + value = module.label8u.context +} + +output "label8u_tags" { + value = module.label8u.tags +} diff --git a/.terraform/modules/datadog_integration.this/examples/complete/versions.tf b/.terraform/modules/datadog_integration.this/examples/complete/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/examples/complete/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration.this/exports/context.tf b/.terraform/modules/datadog_integration.this/exports/context.tf new file mode 100755 index 0000000..81f99b4 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/exports/context.tf @@ -0,0 +1,202 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration.this/main.tf b/.terraform/modules/datadog_integration.this/main.tf new file mode 100755 index 0000000..0deda2b --- /dev/null +++ b/.terraform/modules/datadog_integration.this/main.tf @@ -0,0 +1,146 @@ +locals { + + defaults = { + label_order = ["namespace", "environment", "stage", "name", "attributes"] + regex_replace_chars = "/[^-a-zA-Z0-9]/" + delimiter = "-" + replacement = "" + id_length_limit = 0 + id_hash_length = 5 + label_key_case = "title" + label_value_case = "lower" + } + + # So far, we have decided not to allow overriding replacement or id_hash_length + replacement = local.defaults.replacement + id_hash_length = local.defaults.id_hash_length + + # The values provided by variables supersede the values inherited from the context object, + # except for tags and attributes which are merged. + input = { + # It would be nice to use coalesce here, but we cannot, because it + # is an error for all the arguments to coalesce to be empty. + enabled = var.enabled == null ? var.context.enabled : var.enabled + namespace = var.namespace == null ? var.context.namespace : var.namespace + environment = var.environment == null ? var.context.environment : var.environment + stage = var.stage == null ? var.context.stage : var.stage + name = var.name == null ? var.context.name : var.name + delimiter = var.delimiter == null ? var.context.delimiter : var.delimiter + # modules tack on attributes (passed by var) to the end of the list (passed by context) + attributes = compact(distinct(concat(coalesce(var.context.attributes, []), coalesce(var.attributes, [])))) + tags = merge(var.context.tags, var.tags) + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + label_order = var.label_order == null ? var.context.label_order : var.label_order + regex_replace_chars = var.regex_replace_chars == null ? var.context.regex_replace_chars : var.regex_replace_chars + id_length_limit = var.id_length_limit == null ? var.context.id_length_limit : var.id_length_limit + label_key_case = var.label_key_case == null ? lookup(var.context, "label_key_case", null) : var.label_key_case + label_value_case = var.label_value_case == null ? lookup(var.context, "label_value_case", null) : var.label_value_case + } + + + enabled = local.input.enabled + regex_replace_chars = coalesce(local.input.regex_replace_chars, local.defaults.regex_replace_chars) + + # string_label_names are names of inputs that are strings (not list of strings) used as labels + string_label_names = ["name", "namespace", "environment", "stage"] + normalized_labels = { for k in local.string_label_names : k => + local.input[k] == null ? "" : replace(local.input[k], local.regex_replace_chars, local.replacement) + } + normalized_attributes = compact(distinct([for v in local.input.attributes : replace(v, local.regex_replace_chars, local.replacement)])) + + formatted_labels = { for k in local.string_label_names : k => local.label_value_case == "none" ? local.normalized_labels[k] : + local.label_value_case == "title" ? title(lower(local.normalized_labels[k])) : + local.label_value_case == "upper" ? upper(local.normalized_labels[k]) : lower(local.normalized_labels[k]) + } + + attributes = compact(distinct([ + for v in local.normalized_attributes : (local.label_value_case == "none" ? v : + local.label_value_case == "title" ? title(lower(v)) : + local.label_value_case == "upper" ? upper(v) : lower(v)) + ])) + + name = local.formatted_labels["name"] + namespace = local.formatted_labels["namespace"] + environment = local.formatted_labels["environment"] + stage = local.formatted_labels["stage"] + + delimiter = local.input.delimiter == null ? local.defaults.delimiter : local.input.delimiter + label_order = local.input.label_order == null ? local.defaults.label_order : coalescelist(local.input.label_order, local.defaults.label_order) + id_length_limit = local.input.id_length_limit == null ? local.defaults.id_length_limit : local.input.id_length_limit + label_key_case = local.input.label_key_case == null ? local.defaults.label_key_case : local.input.label_key_case + label_value_case = local.input.label_value_case == null ? local.defaults.label_value_case : local.input.label_value_case + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + + tags = merge(local.generated_tags, local.input.tags) + + tags_as_list_of_maps = flatten([ + for key in keys(local.tags) : merge( + { + key = key + value = local.tags[key] + }, var.additional_tag_map) + ]) + + tags_context = { + # For AWS we need `Name` to be disambiguated since it has a special meaning + name = local.id + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = local.id_context.attributes + } + + generated_tags = { + for l in keys(local.tags_context) : + local.label_key_case == "upper" ? upper(l) : ( + local.label_key_case == "lower" ? lower(l) : title(lower(l)) + ) => local.tags_context[l] if length(local.tags_context[l]) > 0 + } + + id_context = { + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = join(local.delimiter, local.attributes) + } + + labels = [for l in local.label_order : local.id_context[l] if length(local.id_context[l]) > 0] + + id_full = join(local.delimiter, local.labels) + # Create a truncated ID if needed + delimiter_length = length(local.delimiter) + # Calculate length of normal part of ID, leaving room for delimiter and hash + id_truncated_length_limit = local.id_length_limit - (local.id_hash_length + local.delimiter_length) + # Truncate the ID and ensure a single (not double) trailing delimiter + id_truncated = local.id_truncated_length_limit <= 0 ? "" : "${trimsuffix(substr(local.id_full, 0, local.id_truncated_length_limit), local.delimiter)}${local.delimiter}" + # Support usages that disallow numeric characters. Would prefer tr 0-9 q-z but Terraform does not support it. + id_hash_plus = "${md5(local.id_full)}qrstuvwxyz" + id_hash_case = local.label_value_case == "title" ? title(local.id_hash_plus) : local.label_value_case == "upper" ? upper(local.id_hash_plus) : local.label_value_case == "lower" ? lower(local.id_hash_plus) : local.id_hash_plus + id_hash = replace(local.id_hash_case, local.regex_replace_chars, local.replacement) + # Create the short ID by adding a hash to the end of the truncated ID + id_short = substr("${local.id_truncated}${local.id_hash}", 0, local.id_length_limit) + id = local.id_length_limit != 0 && length(local.id_full) > local.id_length_limit ? local.id_short : local.id_full + + + # Context of this label to pass to other label modules + output_context = { + enabled = local.enabled + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + delimiter = local.delimiter + attributes = local.attributes + tags = local.tags + additional_tag_map = local.additional_tag_map + label_order = local.label_order + regex_replace_chars = local.regex_replace_chars + id_length_limit = local.id_length_limit + label_key_case = local.label_key_case + label_value_case = local.label_value_case + } + +} diff --git a/.terraform/modules/datadog_integration.this/outputs.tf b/.terraform/modules/datadog_integration.this/outputs.tf new file mode 100755 index 0000000..87ad1be --- /dev/null +++ b/.terraform/modules/datadog_integration.this/outputs.tf @@ -0,0 +1,88 @@ +output "id" { + value = local.enabled ? local.id : "" + description = "Disambiguated ID restricted to `id_length_limit` characters in total" +} + +output "id_full" { + value = local.enabled ? local.id_full : "" + description = "Disambiguated ID not restricted in length" +} + +output "enabled" { + value = local.enabled + description = "True if module is enabled, false otherwise" +} + +output "namespace" { + value = local.enabled ? local.namespace : "" + description = "Normalized namespace" +} + +output "environment" { + value = local.enabled ? local.environment : "" + description = "Normalized environment" +} + +output "name" { + value = local.enabled ? local.name : "" + description = "Normalized name" +} + +output "stage" { + value = local.enabled ? local.stage : "" + description = "Normalized stage" +} + +output "delimiter" { + value = local.enabled ? local.delimiter : "" + description = "Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes`" +} + +output "attributes" { + value = local.enabled ? local.attributes : [] + description = "List of attributes" +} + +output "tags" { + value = local.enabled ? local.tags : {} + description = "Normalized Tag map" +} + +output "additional_tag_map" { + value = local.additional_tag_map + description = "The merged additional_tag_map" +} + +output "label_order" { + value = local.label_order + description = "The naming order actually used to create the ID" +} + +output "regex_replace_chars" { + value = local.regex_replace_chars + description = "The regex_replace_chars actually used to create the ID" +} + +output "id_length_limit" { + value = local.id_length_limit + description = "The id_length_limit actually used to create the ID, with `0` meaning unlimited" +} + +output "tags_as_list_of_maps" { + value = local.tags_as_list_of_maps + description = "Additional tags as a list of maps, which can be used in several AWS resources" +} + +output "normalized_context" { + value = local.output_context + description = "Normalized context of this module" +} + +output "context" { + value = local.input + description = <<-EOT + Merged but otherwise unmodified input to this module, to be used as context input to other modules. + Note: this version will have null values as defaults, not the values actually used as defaults. +EOT +} + diff --git a/.terraform/modules/datadog_integration.this/test/Makefile b/.terraform/modules/datadog_integration.this/test/Makefile new file mode 100755 index 0000000..ea15d62 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/test/Makefile @@ -0,0 +1,43 @@ +TEST_HARNESS ?= https://github.com/cloudposse/test-harness.git +TEST_HARNESS_BRANCH ?= master +TEST_HARNESS_PATH = $(realpath .test-harness) +BATS_ARGS ?= --tap +BATS_LOG ?= test.log + +# Define a macro to run the tests +define RUN_TESTS +@echo "Running tests in $(1)" +@cd $(1) && bats $(BATS_ARGS) $(addsuffix .bats,$(addprefix $(TEST_HARNESS_PATH)/test/terraform/,$(TESTS))) +endef + +default: all + +-include Makefile.* + +## Provision the test-harnesss +.test-harness: + [ -d $@ ] || git clone --depth=1 -b $(TEST_HARNESS_BRANCH) $(TEST_HARNESS) $@ + +## Initialize the tests +init: .test-harness + +## Install all dependencies (OS specific) +deps:: + @exit 0 + +## Clean up the test harness +clean: + [ "$(TEST_HARNESS_PATH)" == "/" ] || rm -rf $(TEST_HARNESS_PATH) + +## Run all tests +all: module examples/complete + +## Run basic sanity checks against the module itself +module: export TESTS ?= installed lint get-modules module-pinning get-plugins provider-pinning validate terraform-docs input-descriptions output-descriptions +module: deps + $(call RUN_TESTS, ../) + +## Run tests against example +examples/complete: export TESTS ?= installed lint get-modules get-plugins validate init plan apply +examples/complete: deps + $(call RUN_TESTS, ../$@) diff --git a/.terraform/modules/datadog_integration.this/test/Makefile.alpine b/.terraform/modules/datadog_integration.this/test/Makefile.alpine new file mode 100755 index 0000000..7925b18 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/test/Makefile.alpine @@ -0,0 +1,5 @@ +ifneq (,$(wildcard /sbin/apk)) +## Install all dependencies for alpine +deps:: init + @apk add --update terraform-docs@cloudposse json2hcl@cloudposse +endif diff --git a/.terraform/modules/datadog_integration.this/test/src/Makefile b/.terraform/modules/datadog_integration.this/test/src/Makefile new file mode 100755 index 0000000..b772822 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/test/src/Makefile @@ -0,0 +1,30 @@ +export TF_CLI_ARGS_init ?= -get-plugins=true +export TERRAFORM_VERSION ?= $(shell curl -s https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r -M '.current_version' | cut -d. -f1-2) + +.DEFAULT_GOAL : all +.PHONY: all + +## Default target +all: test + +.PHONY : init +## Initialize tests +init: + @exit 0 + +.PHONY : test +## Run tests +test: init + go mod download + go test -v -timeout 60m -run TestExamplesComplete + +## Run tests in docker container +docker/test: + docker run --name terratest --rm -it -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e GITHUB_TOKEN \ + -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" \ + -v $(CURDIR)/../../:/module/ cloudposse/test-harness:latest -C /module/test/src test + +.PHONY : clean +## Clean up files +clean: + rm -rf ../../examples/complete/*.tfstate* diff --git a/.terraform/modules/datadog_integration.this/test/src/examples_complete_test.go b/.terraform/modules/datadog_integration.this/test/src/examples_complete_test.go new file mode 100755 index 0000000..156e293 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/test/src/examples_complete_test.go @@ -0,0 +1,293 @@ +package test + +import ( + "fmt" + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" + "github.com/qdm12/reprint" + "github.com/stretchr/testify/assert" +) + +type NLContext struct { + AdditionalTagMap map[string]string `json:"additional_tag_map"` + Attributes []string `json:"attributes"` + Delimiter interface{} `json:"delimiter"` + Enabled bool `json:"enabled"` + Environment interface{} `json:"environment"` + LabelOrder []string `json:"label_order"` + Name interface{} `json:"name"` + Namespace interface{} `json:"namespace"` + RegexReplaceChars interface{} `json:"regex_replace_chars"` + Stage interface{} `json:"stage"` + Tags map[string]string `json:"tags"` +} + +// Test the Terraform module in examples/complete using Terratest. +func TestExamplesComplete(t *testing.T) { + t.Parallel() + + terraformOptions := &terraform.Options{ + // The path to where our Terraform code is located + TerraformDir: "../../examples/complete", + Upgrade: true, + } + + // At the end of the test, run `terraform destroy` to clean up any resources that were created + defer terraform.Destroy(t, terraformOptions) + + // This will run `terraform init` and `terraform apply` and fail the test if there are any errors + terraform.InitAndApply(t, terraformOptions) + + expectedLabel1Context := NLContext{ + Enabled: true, + Namespace: "CloudPosse", + Environment: "UAT", + Stage: "build", + Name: "Winston Churchroom", + Attributes: []string{"fire", "water", "earth", "air"}, + Delimiter: "-", + LabelOrder: []string{"name", "environment", "stage", "attributes"}, + Tags: map[string]string{ + "City": "Dublin", + "Environment": "Private", + }, + AdditionalTagMap: map[string]string{}, + } + + var expectedLabel1NormalizedContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel1NormalizedContext) + expectedLabel1NormalizedContext.Namespace = "cloudposse" + expectedLabel1NormalizedContext.Environment = "uat" + expectedLabel1NormalizedContext.Name = "winstonchurchroom" + expectedLabel1NormalizedContext.RegexReplaceChars = "/[^-a-zA-Z0-9]/" + expectedLabel1NormalizedContext.Tags = map[string]string{ + "City": "Dublin", + "Environment": "Private", + "Namespace": "cloudposse", + "Stage": "build", + "Name": "winstonchurchroom-uat-build-fire-water-earth-air", + "Attributes": "fire-water-earth-air", + } + + var label1NormalizedContext, label1Context NLContext + // Run `terraform output` to get the value of an output variable + label1 := terraform.OutputMap(t, terraformOptions, "label1") + label1Tags := terraform.OutputMap(t, terraformOptions, "label1_tags") + terraform.OutputStruct(t, terraformOptions, "label1_normalized_context", &label1NormalizedContext) + terraform.OutputStruct(t, terraformOptions, "label1_context", &label1Context) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1["id"]) + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1Tags["Name"]) + assert.Equal(t, "Dublin", label1Tags["City"]) + assert.Equal(t, "Private", label1Tags["Environment"]) + assert.Equal(t, expectedLabel1NormalizedContext, label1NormalizedContext) + assert.Equal(t, expectedLabel1Context, label1Context) + + label1t1 := terraform.OutputMap(t, terraformOptions, "label1t1") + label1t1Tags := terraform.OutputMap(t, terraformOptions, "label1t1_tags") + assert.Equal(t, "winstonchurchroom-uat-6a0b34", label1t1["id"], + "Extra hash character should be added when trailing delimiter is removed") + assert.Equal(t, label1["id"], label1t1["id_full"], "id_full should not be truncated") + assert.Equal(t, label1t1["id"], label1t1Tags["Name"], "Name tag should match ID") + + label1t2 := terraform.OutputMap(t, terraformOptions, "label1t2") + label1t2Tags := terraform.OutputMap(t, terraformOptions, "label1t2_tags") + assert.Equal(t, "winstonchurchroom-uat-b-6a0b3", label1t2["id"]) + assert.Equal(t, label1t2["id"], label1t2Tags["Name"], "Name tag should match ID") + + // Run `terraform output` to get the value of an output variable + label2 := terraform.OutputMap(t, terraformOptions, "label2") + label2Tags := terraform.OutputMap(t, terraformOptions, "label2_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2["id"]) + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2Tags["Name"]) + assert.Equal(t, "London", label2Tags["City"]) + assert.Equal(t, "Public", label2Tags["Environment"]) + + var expectedLabel3cContext, label3cContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel3cContext) + expectedLabel3cContext.Name = "Starfish" + expectedLabel3cContext.Stage = "release" + expectedLabel3cContext.Delimiter = "." + expectedLabel3cContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3cContext.Tags["Eat"] = "Carrot" + expectedLabel3cContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3c := terraform.OutputMap(t, terraformOptions, "label3c") + label3cTags := terraform.OutputMap(t, terraformOptions, "label3c_tags") + terraform.OutputStruct(t, terraformOptions, "label3c_context", &label3cContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3c["id"]) + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3cTags["Name"]) + assert.Equal(t, expectedLabel3cContext, label3cContext) + + var expectedLabel3nContext, label3nContext NLContext + _ = reprint.FromTo(&expectedLabel1NormalizedContext, &expectedLabel3nContext) + expectedLabel3nContext.Name = "Starfish" + expectedLabel3nContext.Stage = "release" + expectedLabel3nContext.Delimiter = "." + expectedLabel3nContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3nContext.Tags["Eat"] = "Carrot" + expectedLabel3nContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3n := terraform.OutputMap(t, terraformOptions, "label3n") + label3nTags := terraform.OutputMap(t, terraformOptions, "label3n_tags") + terraform.OutputStruct(t, terraformOptions, "label3n_context", &label3nContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3n["id"]) + assert.Equal(t, label1Tags["Name"], label3nTags["Name"], + "Tag from label1 normalized context should overwrite label3n generated tag") + assert.Equal(t, expectedLabel3nContext, label3nContext) + + // Run `terraform output` to get the value of an output variable + label4 := terraform.OutputMap(t, terraformOptions, "label4") + label4Tags := terraform.OutputMap(t, terraformOptions, "label4_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4["id"]) + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4Tags["Name"]) + + // Run `terraform output` to get the value of an output variable + label5 := terraform.OutputMap(t, terraformOptions, "label5") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "", label5["id"]) + + label6f := terraform.OutputMap(t, terraformOptions, "label6f") + label6fTags := terraform.OutputMap(t, terraformOptions, "label6f_tags") + // Test of setting var.label_key_case = "lower", var.label_value_case = "upper" + assert.Equal(t, "CP~UW2~PRD~NULL-LABEL", label6f["id_full"]) + assert.Equal(t, label6f["id_full"], label6f["id"], "id should not be truncated") + assert.Equal(t, label6f["id"], label6fTags["name"], "Name tag should match ID") + + label6t := terraform.OutputMap(t, terraformOptions, "label6t") + label6tTags := terraform.OutputMap(t, terraformOptions, "label6t_tags") + assert.Equal(t, "CPUW2PRDNULL-LABEL", label6t["id_full"]) + assert.NotEqual(t, label6t["id_full"], label6t["id"], "id should be truncated") + assert.Equal(t, label6t["id"], label6tTags["name"], "Name tag should match ID") + assert.Equal(t, label6t["id_length_limit"], fmt.Sprintf("%d", len(label6t["id"])), + "Truncated ID length should equal length limit") + + label7 := terraform.OutputMap(t, terraformOptions, "label7") + assert.Equal(t, "eg-demo-blue-cluster-nodegroup", label7["id"], "var.attributes should be appended after context.attributes") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter=""` returns expected value of id, context id + label8dndID := terraform.Output(t, terraformOptions, "label8dnd_id") + label8dndContextID := terraform.Output(t, terraformOptions, "label8dnd_context_id") + assert.Equal(t, "egdemobluecluster", label8dndID) + assert.Equal(t, label8dndID, label8dndContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter="x"` returns expected value of id, context id + label8dcdID := terraform.Output(t, terraformOptions, "label8dcd_id") + label8dcdContextID := terraform.Output(t, terraformOptions, "label8dcd_context_id") + assert.Equal(t, "egxdemoxbluexcluster", label8dcdID) + assert.Equal(t, label8dcdID, label8dcdContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=lower` returns expected values of id, tags, context tags + label8dExpectedTags := map[string]string{ + "Attributes": "cluster", + "Environment": "demo", + "Name": "eg-demo-blue-cluster", + "Namespace": "eg", + "kubernetes.io/cluster/": "shared", + } + + label8dID := terraform.Output(t, terraformOptions, "label8d_id") + label8dContextID := terraform.Output(t, terraformOptions, "label8d_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8dID) + assert.Equal(t, label8dID, label8dContextID, "ID and context ID should be equal") + + label8dTags := terraform.OutputMap(t, terraformOptions, "label8d_tags") + label8dContextTags := terraform.OutputMap(t, terraformOptions, "label8d_context_tags") + + assert.Exactly(t, label8dExpectedTags, label8dTags, "generated tags are different from expected") + assert.Exactly(t, label8dTags, label8dContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=lower` and `label_value_case=lower` returns expected values of id, tags, context tags + label8lExpectedTags := map[string]string{ + "attributes": "cluster", + "environment": "demo", + "name": "eg-demo-blue-cluster", + "namespace": "eg", + "kubernetes.io/cluster/": "shared", + "upperTEST": "testUPPER", + } + + label8lID := terraform.Output(t, terraformOptions, "label8l_id") + label8lContextID := terraform.Output(t, terraformOptions, "label8l_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8lID) + assert.Equal(t, label8lID, label8lContextID, "ID and context ID should be equal") + + label8lTags := terraform.OutputMap(t, terraformOptions, "label8l_tags") + label8lContextTags := terraform.OutputMap(t, terraformOptions, "label8l_context_tags") + + assert.Exactly(t, label8lExpectedTags, label8lTags, "generated tags are different from expected") + assert.Exactly(t, label8lTags, label8lContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=title` returns expected values of id, tags, context tags + label8tExpectedTags := map[string]string{ + "Attributes": "Eks-Cluster", + "Environment": "Demo", + "Name": "Eg-Demo-Blue-Eks-Cluster", + "Namespace": "Eg", + "kubernetes.io/cluster/": "shared", + } + + label8tID := terraform.Output(t, terraformOptions, "label8t_id") + label8tContextID := terraform.Output(t, terraformOptions, "label8t_context_id") + assert.Equal(t, "Eg-Demo-Blue-Eks-Cluster", label8tID) + assert.Equal(t, label8tID, label8tContextID, "ID and context ID should be equal") + + label8tTags := terraform.OutputMap(t, terraformOptions, "label8t_tags") + label8tContextTags := terraform.OutputMap(t, terraformOptions, "label8t_context_tags") + + assert.Exactly(t, label8tExpectedTags, label8tTags, "generated tags are different from expected") + assert.Exactly(t, label8tTags, label8tContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=upper` and `label_value_case=upper` returns expected values of id, tags, context tags + label8uExpectedTags := map[string]string{ + "ATTRIBUTES": "CLUSTER", + "ENVIRONMENT": "DEMO", + "NAME": "EG-DEMO-BLUE-CLUSTER", + "NAMESPACE": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8uID := terraform.Output(t, terraformOptions, "label8u_id") + label8uContextID := terraform.Output(t, terraformOptions, "label8u_context_id") + assert.Equal(t, "EG-DEMO-BLUE-CLUSTER", label8uID) + assert.Equal(t, label8uID, label8uContextID, "ID and context ID should be equal") + + label8uTags := terraform.OutputMap(t, terraformOptions, "label8u_tags") + label8uContextTags := terraform.OutputMap(t, terraformOptions, "label8u_context_tags") + + assert.Exactly(t, label8uExpectedTags, label8uTags, "generated tags are different from expected") + assert.Exactly(t, label8uTags, label8uContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=none` returns expected values of id, tags, context tags + label8nExpectedTags := map[string]string{ + "Attributes": "eks-ClusteR", + "Environment": "demo", + "Name": "EG-demo-blue-eks-ClusteR", + "Namespace": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8nID := terraform.Output(t, terraformOptions, "label8n_id") + label8nContextID := terraform.Output(t, terraformOptions, "label8n_context_id") + assert.Equal(t, "EG-demo-blue-eks-ClusteR", label8nID) + assert.Equal(t, label8nID, label8nContextID, "ID and context ID should be equal") + + label8nTags := terraform.OutputMap(t, terraformOptions, "label8n_tags") + label8nContextTags := terraform.OutputMap(t, terraformOptions, "label8n_context_tags") + + assert.Exactly(t, label8nExpectedTags, label8nTags, "generated tags are different from expected") + assert.Exactly(t, label8nTags, label8nContextTags, "tags and context tags should be equal") +} diff --git a/.terraform/modules/datadog_integration.this/test/src/go.mod b/.terraform/modules/datadog_integration.this/test/src/go.mod new file mode 100755 index 0000000..d866541 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/test/src/go.mod @@ -0,0 +1,9 @@ +module github.com/cloudposse/terraform-null-label + +go 1.14 + +require ( + github.com/gruntwork-io/terratest v0.31.1 + github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 + github.com/stretchr/testify v1.6.1 +) diff --git a/.terraform/modules/datadog_integration.this/test/src/go.sum b/.terraform/modules/datadog_integration.this/test/src/go.sum new file mode 100755 index 0000000..b8d46b1 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/test/src/go.sum @@ -0,0 +1,595 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= +github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.5/go.mod h1:foo3aIXRQ90zFve3r0QiDsrjGDUwWhKl0ZOQy1CT14k= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= +github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200109221225-a4f60165b7a3/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= +github.com/gruntwork-io/terratest v0.31.1 h1:MPGe/5pGgJAIZ/hb+0LM1KyJKSi/QyxSkHoP9/CBhJg= +github.com/gruntwork-io/terratest v0.31.1/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= +github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4= +github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= +github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= +k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= +k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= +k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= +k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= +k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= +k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= +k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= +modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/.terraform/modules/datadog_integration.this/variables.tf b/.terraform/modules/datadog_integration.this/variables.tf new file mode 100755 index 0000000..40fb268 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/variables.tf @@ -0,0 +1,157 @@ +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} diff --git a/.terraform/modules/datadog_integration.this/versions.tf b/.terraform/modules/datadog_integration.this/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration.this/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration2 b/.terraform/modules/datadog_integration2 new file mode 160000 index 0000000..59c8066 --- /dev/null +++ b/.terraform/modules/datadog_integration2 @@ -0,0 +1 @@ +Subproject commit 59c8066eceee715d72f18dfd64836abb777aa22b diff --git a/.terraform/modules/datadog_integration2.all_label b/.terraform/modules/datadog_integration2.all_label new file mode 160000 index 0000000..dc69999 --- /dev/null +++ b/.terraform/modules/datadog_integration2.all_label @@ -0,0 +1 @@ +Subproject commit dc699992922b452ccc521c3dfe9c9c5c1f8376af diff --git a/.terraform/modules/datadog_integration2.core_label/LICENSE b/.terraform/modules/datadog_integration2.core_label/LICENSE new file mode 100755 index 0000000..c844c70 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017-2020 Cloud Posse, LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/.terraform/modules/datadog_integration2.core_label/Makefile b/.terraform/modules/datadog_integration2.core_label/Makefile new file mode 100755 index 0000000..97d8087 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/Makefile @@ -0,0 +1,10 @@ +SHELL := /bin/bash + +# List of targets the `readme` target should call before generating the readme +export README_DEPS ?= docs/targets.md docs/terraform.md + +-include $(shell curl -sSL -o .build-harness "https://git.io/build-harness"; echo .build-harness) + +## Lint terraform code +lint: + $(SELF) terraform/install terraform/get-modules terraform/get-plugins terraform/lint terraform/validate diff --git a/.terraform/modules/datadog_integration2.core_label/README.md b/.terraform/modules/datadog_integration2.core_label/README.md new file mode 100755 index 0000000..32950e4 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/README.md @@ -0,0 +1,938 @@ + +# terraform-null-label [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-null-label.svg)](https://github.com/cloudposse/terraform-null-label/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) + + +[![README Header][readme_header_img]][readme_header_link] + +[![Cloud Posse][logo]](https://cpco.io/homepage) + + + +Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + +This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. +However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). +So if you prefer the term `stage` to `environment` +you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. +- If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. +- If you want the attributes in a different order, you can specify that, too, with the `label_order` list. +- You can set a maximum length for the name, and the module will create a unique name that fits within that length. +- You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. +- The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + +It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. +For example, if you have 10 instances, there should be 10 different labels. +However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + +All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + +**NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. +With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + +- Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. +- Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. +- Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. + + +--- + +This project is part of our comprehensive ["SweetOps"](https://cpco.io/sweetops) approach towards DevOps. +[][share_email] +[][share_googleplus] +[][share_facebook] +[][share_reddit] +[][share_linkedin] +[][share_twitter] + + +[![Terraform Open Source Modules](https://docs.cloudposse.com/images/terraform-open-source-modules.svg)][terraform_modules] + + + +It's 100% Open Source and licensed under the [APACHE2](LICENSE). + + + + + + + +We literally have [*hundreds of terraform modules*][terraform_modules] that are Open Source and well-maintained. Check them out! + + + + + + + +## Security & Compliance [](https://bridgecrew.io/) + +Security scanning is graciously provided by Bridgecrew. Bridgecrew is the leading fully hosted, cloud-native solution providing continuous Terraform security and compliance. + +| Benchmark | Description | +|--------|---------------| +| [![Infrastructure Security](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/general)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=INFRASTRUCTURE+SECURITY) | Infrastructure Security Compliance | +| [![CIS KUBERNETES](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_kubernetes)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+KUBERNETES+V1.5) | Center for Internet Security, KUBERNETES Compliance | +| [![CIS AWS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_aws)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AWS+V1.2) | Center for Internet Security, AWS Compliance | +| [![CIS AZURE](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_azure)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AZURE+V1.1) | Center for Internet Security, AZURE Compliance | +| [![PCI-DSS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/pci)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=PCI-DSS+V3.2) | Payment Card Industry Data Security Standards Compliance | +| [![NIST-800-53](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/nist)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=NIST-800-53) | National Institute of Standards and Technology Compliance | +| [![ISO27001](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/iso)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=ISO27001) | Information Security Management System, ISO/IEC 27001 Compliance | +| [![SOC2](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/soc2)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=SOC2)| Service Organization Control 2 Compliance | +| [![CIS GCP](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_gcp)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+GCP+V1.1) | Center for Internet Security, GCP Compliance | +| [![HIPAA](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/hipaa)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=HIPAA) | Health Insurance Portability and Accountability Compliance | + + + +## Usage + + +**IMPORTANT:** We do not pin modules to versions in our examples because of the +difficulty of keeping the versions in the documentation in sync with the latest released versions. +We highly recommend that in your code you pin the version to the exact version you are +using so that your infrastructure remains stable, and update versions in a +systematic way so that they do not catch you by surprise. + +Also, because of a bug in the Terraform registry ([hashicorp/terraform#21417](https://github.com/hashicorp/terraform/issues/21417)), +the registry shows many of our inputs as required when in fact they are optional. +The table below correctly indicates which inputs are required. + + +### Defaults + +Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. +The context object is a single object that contains all the input values for `terraform-null-label`. +However, each input value can also be specified individually by name as a standard Terraform variable, +and the value of those variables, when set to something other than `null`, will override the value +in the context object. In order to allow chaining of these objects, where the context object input to one +module is transformed and passed to the next module, all the variables default to `null` or empty collections. +The actual default values used when nothing is explicitly set are describe in the documentation below. + +For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, +`terraform-null-label` will actually use the default delimiter `-` (hyphen). + +A non-obvious but intentional consequence of this design is that once a module sets a non-default value, +future modules in the chain cannot reset the value back to the original default. Insted, the new setting +becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, +so once a tag is added, it will remain in the tag set and cannot be removed, although its value can +be overwritten. + +### Simple Example + +```hcl +module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} +``` + +This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` +(you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + +Now reference the label when creating an instance: + +```hcl +resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags +} +``` + +Or define a security group: + +```hcl +resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} +``` + + +### Advanced Example + +Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + +```hcl +module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] +} + +module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] +} +``` + +
+ +### Advanced Example 2 + +Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + +```hcl +tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } +] +``` + +Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + +```hcl +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} +``` + +
+ +### Advanced Example 3 + +See [complete example](./examples/complete) for even more examples. + +This example shows how you can pass the `context` output of one label module to the next label_module, +allowing you to create one label that has the base set of values, and then creating every extra label +as a derivative of that. + +
Click to show + +```hcl +module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} +``` + +This creates label outputs like this: + +```hcl +label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" +} +label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } +} +label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } +} +label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" +} +label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" +} +label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } +} +label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" +} +label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, +] +label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" +} +label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } +} +label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } +} +label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" +} + +``` + +
+ + + + + + + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + + + + +## Share the Love + +Like this project? Please give it a ★ on [our GitHub](https://github.com/cloudposse/terraform-null-label)! (it helps us **a lot**) + +Are you using this project or any of our other projects? Consider [leaving a testimonial][testimonial]. =) + + +## Related Projects + +Check out these related projects. + +- [terraform-terraform-label](https://github.com/cloudposse/terraform-terraform-label) - Terraform Module to define a consistent naming convention by (namespace, environment, stage, name, [attributes]) + + + +## Help + +**Got a question?** We got answers. + +File a GitHub [issue](https://github.com/cloudposse/terraform-null-label/issues), send us an [email][email] or join our [Slack Community][slack]. + +[![README Commercial Support][readme_commercial_support_img]][readme_commercial_support_link] + +## DevOps Accelerator for Startups + + +We are a [**DevOps Accelerator**][commercial_support]. We'll help you build your cloud infrastructure from the ground up so you can own it. Then we'll show you how to operate it and stick around for as long as you need us. + +[![Learn More](https://img.shields.io/badge/learn%20more-success.svg?style=for-the-badge)][commercial_support] + +Work directly with our team of DevOps experts via email, slack, and video conferencing. + +We deliver 10x the value for a fraction of the cost of a full-time engineer. Our track record is not even funny. If you want things done right and you need it done FAST, then we're your best bet. + +- **Reference Architecture.** You'll get everything you need from the ground up built using 100% infrastructure as code. +- **Release Engineering.** You'll have end-to-end CI/CD with unlimited staging environments. +- **Site Reliability Engineering.** You'll have total visibility into your apps and microservices. +- **Security Baseline.** You'll have built-in governance with accountability and audit logs for all changes. +- **GitOps.** You'll be able to operate your infrastructure via Pull Requests. +- **Training.** You'll receive hands-on training so your team can operate what we build. +- **Questions.** You'll have a direct line of communication between our teams via a Shared Slack channel. +- **Troubleshooting.** You'll get help to triage when things aren't working. +- **Code Reviews.** You'll receive constructive feedback on Pull Requests. +- **Bug Fixes.** We'll rapidly work with you to fix any bugs in our projects. + +## Slack Community + +Join our [Open Source Community][slack] on Slack. It's **FREE** for everyone! Our "SweetOps" community is where you get to talk with others who share a similar vision for how to rollout and manage infrastructure. This is the best place to talk shop, ask questions, solicit feedback, and work together as a community to build totally *sweet* infrastructure. + +## Discourse Forums + +Participate in our [Discourse Forums][discourse]. Here you'll find answers to commonly asked questions. Most questions will be related to the enormous number of projects we support on our GitHub. Come here to collaborate on answers, find solutions, and get ideas about the products and services we value. It only takes a minute to get started! Just sign in with SSO using your GitHub account. + +## Newsletter + +Sign up for [our newsletter][newsletter] that covers everything on our technology radar. Receive updates on what we're up to on GitHub as well as awesome new projects we discover. + +## Office Hours + +[Join us every Wednesday via Zoom][office_hours] for our weekly "Lunch & Learn" sessions. It's **FREE** for everyone! + +[![zoom](https://img.cloudposse.com/fit-in/200x200/https://cloudposse.com/wp-content/uploads/2019/08/Powered-by-Zoom.png")][office_hours] + +## Contributing + +### Bug Reports & Feature Requests + +Please use the [issue tracker](https://github.com/cloudposse/terraform-null-label/issues) to report any bugs or file feature requests. + +### Developing + +If you are interested in being a contributor and want to get involved in developing this project or [help out](https://cpco.io/help-out) with our other projects, we would love to hear from you! Shoot us an [email][email]. + +In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. + + 1. **Fork** the repo on GitHub + 2. **Clone** the project to your own machine + 3. **Commit** changes to your own branch + 4. **Push** your work back up to your fork + 5. Submit a **Pull Request** so that we can review your changes + +**NOTE:** Be sure to merge the latest changes from "upstream" before making a pull request! + + +## Copyright + +Copyright © 2017-2021 [Cloud Posse, LLC](https://cpco.io/copyright) + + + +## License + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +See [LICENSE](LICENSE) for full details. + +```text +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +``` + + + + + + + + + +## Trademarks + +All other trademarks referenced herein are the property of their respective owners. + +## About + +This project is maintained and funded by [Cloud Posse, LLC][website]. Like it? Please let us know by [leaving a testimonial][testimonial]! + +[![Cloud Posse][logo]][website] + +We're a [DevOps Professional Services][hire] company based in Los Angeles, CA. We ❤️ [Open Source Software][we_love_open_source]. + +We offer [paid support][commercial_support] on all of our projects. + +Check out [our other projects][github], [follow us on twitter][twitter], [apply for a job][jobs], or [hire us][hire] to help with your cloud strategy and implementation. + + + +### Contributors + + +| [![Erik Osterman][osterman_avatar]][osterman_homepage]
[Erik Osterman][osterman_homepage] | [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]
[Andriy Knysh][aknysh_homepage] | [![Igor Rodionov][goruha_avatar]][goruha_homepage]
[Igor Rodionov][goruha_homepage] | [![Sergey Vasilyev][s2504s_avatar]][s2504s_homepage]
[Sergey Vasilyev][s2504s_homepage] | [![Michael Pereira][MichaelPereira_avatar]][MichaelPereira_homepage]
[Michael Pereira][MichaelPereira_homepage] | [![Jamie Nelson][Jamie-BitFlight_avatar]][Jamie-BitFlight_homepage]
[Jamie Nelson][Jamie-BitFlight_homepage] | [![Vladimir][SweetOps_avatar]][SweetOps_homepage]
[Vladimir][SweetOps_homepage] | [![Daren Desjardins][darend_avatar]][darend_homepage]
[Daren Desjardins][darend_homepage] | [![Maarten van der Hoef][maartenvanderhoef_avatar]][maartenvanderhoef_homepage]
[Maarten van der Hoef][maartenvanderhoef_homepage] | [![Adam Tibbing][tibbing_avatar]][tibbing_homepage]
[Adam Tibbing][tibbing_homepage] | +|---|---|---|---|---|---|---|---|---|---| + + + [osterman_homepage]: https://github.com/osterman + [osterman_avatar]: https://img.cloudposse.com/150x150/https://github.com/osterman.png + [aknysh_homepage]: https://github.com/aknysh + [aknysh_avatar]: https://img.cloudposse.com/150x150/https://github.com/aknysh.png + [goruha_homepage]: https://github.com/goruha + [goruha_avatar]: https://img.cloudposse.com/150x150/https://github.com/goruha.png + [s2504s_homepage]: https://github.com/s2504s + [s2504s_avatar]: https://img.cloudposse.com/150x150/https://github.com/s2504s.png + [MichaelPereira_homepage]: https://github.com/MichaelPereira + [MichaelPereira_avatar]: https://img.cloudposse.com/150x150/https://github.com/MichaelPereira.png + [Jamie-BitFlight_homepage]: https://github.com/Jamie-BitFlight + [Jamie-BitFlight_avatar]: https://img.cloudposse.com/150x150/https://github.com/Jamie-BitFlight.png + [SweetOps_homepage]: https://github.com/SweetOps + [SweetOps_avatar]: https://img.cloudposse.com/150x150/https://github.com/SweetOps.png + [darend_homepage]: https://github.com/darend + [darend_avatar]: https://img.cloudposse.com/150x150/https://github.com/darend.png + [maartenvanderhoef_homepage]: https://github.com/maartenvanderhoef + [maartenvanderhoef_avatar]: https://img.cloudposse.com/150x150/https://github.com/maartenvanderhoef.png + [tibbing_homepage]: https://github.com/tibbing + [tibbing_avatar]: https://img.cloudposse.com/150x150/https://github.com/tibbing.png + +[![README Footer][readme_footer_img]][readme_footer_link] +[![Beacon][beacon]][website] + + [logo]: https://cloudposse.com/logo-300x69.svg + [docs]: https://cpco.io/docs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=docs + [website]: https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=website + [github]: https://cpco.io/github?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=github + [jobs]: https://cpco.io/jobs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=jobs + [hire]: https://cpco.io/hire?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=hire + [slack]: https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=slack + [linkedin]: https://cpco.io/linkedin?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=linkedin + [twitter]: https://cpco.io/twitter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=twitter + [testimonial]: https://cpco.io/leave-testimonial?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=testimonial + [office_hours]: https://cloudposse.com/office-hours?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=office_hours + [newsletter]: https://cpco.io/newsletter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=newsletter + [discourse]: https://ask.sweetops.com/?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=discourse + [email]: https://cpco.io/email?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=email + [commercial_support]: https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=commercial_support + [we_love_open_source]: https://cpco.io/we-love-open-source?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=we_love_open_source + [terraform_modules]: https://cpco.io/terraform-modules?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=terraform_modules + [readme_header_img]: https://cloudposse.com/readme/header/img + [readme_header_link]: https://cloudposse.com/readme/header/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_header_link + [readme_footer_img]: https://cloudposse.com/readme/footer/img + [readme_footer_link]: https://cloudposse.com/readme/footer/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_footer_link + [readme_commercial_support_img]: https://cloudposse.com/readme/commercial-support/img + [readme_commercial_support_link]: https://cloudposse.com/readme/commercial-support/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_commercial_support_link + [share_twitter]: https://twitter.com/intent/tweet/?text=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_linkedin]: https://www.linkedin.com/shareArticle?mini=true&title=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_reddit]: https://reddit.com/submit/?url=https://github.com/cloudposse/terraform-null-label + [share_facebook]: https://facebook.com/sharer/sharer.php?u=https://github.com/cloudposse/terraform-null-label + [share_googleplus]: https://plus.google.com/share?url=https://github.com/cloudposse/terraform-null-label + [share_email]: mailto:?subject=terraform-null-label&body=https://github.com/cloudposse/terraform-null-label + [beacon]: https://ga-beacon.cloudposse.com/UA-76589703-4/cloudposse/terraform-null-label?pixel&cs=github&cm=readme&an=terraform-null-label diff --git a/.terraform/modules/datadog_integration2.core_label/README.yaml b/.terraform/modules/datadog_integration2.core_label/README.yaml new file mode 100755 index 0000000..42bdb84 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/README.yaml @@ -0,0 +1,618 @@ +name: terraform-null-label +tags: +- aws +- terraform +- terraform-modules +- naming-convention +- name +- namespace +- stage +categories: +- terraform-modules/supported +license: APACHE2 +github_repo: cloudposse/terraform-null-label +badges: +- name: Latest Release + image: https://img.shields.io/github/release/cloudposse/terraform-null-label.svg + url: https://github.com/cloudposse/terraform-null-label/releases/latest +- name: Slack Community + image: https://slack.cloudposse.com/badge.svg + url: https://slack.cloudposse.com +related: +- name: terraform-terraform-label + description: Terraform Module to define a consistent naming convention by (namespace, + environment, stage, name, [attributes]) + url: https://github.com/cloudposse/terraform-terraform-label +description: |- + Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + + This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. + However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). + So if you prefer the term `stage` to `environment` + you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. + - If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. + - If you want the attributes in a different order, you can specify that, too, with the `label_order` list. + - You can set a maximum length for the name, and the module will create a unique name that fits within that length. + - You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. + - The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + + It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. + For example, if you have 10 instances, there should be 10 different labels. + However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + + All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + + **NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. + With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + + - Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. + - Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. + - Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. +usage: |- + ### Defaults + + Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. + The context object is a single object that contains all the input values for `terraform-null-label`. + However, each input value can also be specified individually by name as a standard Terraform variable, + and the value of those variables, when set to something other than `null`, will override the value + in the context object. In order to allow chaining of these objects, where the context object input to one + module is transformed and passed to the next module, all the variables default to `null` or empty collections. + The actual default values used when nothing is explicitly set are describe in the documentation below. + + For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, + `terraform-null-label` will actually use the default delimiter `-` (hyphen). + + A non-obvious but intentional consequence of this design is that once a module sets a non-default value, + future modules in the chain cannot reset the value back to the original default. Insted, the new setting + becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, + so once a tag is added, it will remain in the tag set and cannot be removed, although its value can + be overwritten. + + ### Simple Example + + ```hcl + module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + ``` + + This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` + (you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + + Now reference the label when creating an instance: + + ```hcl + resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags + } + ``` + + Or define a security group: + + ```hcl + resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + } + ``` + + + ### Advanced Example + + Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + + ```hcl + module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] + } + + module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] + } + ``` + +
+ + ### Advanced Example 2 + + Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + + ```hcl + tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } + ] + ``` + + Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + + ```hcl + ################################ + # terraform-null-label example # + ################################ + module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } + } + + ####################### + # Launch template # + ####################### + resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } + } + + ###################### + # Autoscaling group # + ###################### + resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps + } + ``` + +
+ + ### Advanced Example 3 + + See [complete example](./examples/complete) for even more examples. + + This example shows how you can pass the `context` output of one label module to the next label_module, + allowing you to create one label that has the base set of values, and then creating every extra label + as a derivative of that. + +
Click to show + + ```hcl + module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } + } + + module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } + } + + module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } + } + ``` + + This creates label outputs like this: + + ```hcl + label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" + } + label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } + } + label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + } + label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" + } + label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } + } + label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" + } + label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, + ] + label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" + } + label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } + } + label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + } + label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + + ``` + +
+ +include: +- docs/targets.md +- docs/terraform.md +contributors: +- name: Erik Osterman + github: osterman +- name: Andriy Knysh + github: aknysh +- name: Igor Rodionov + github: goruha +- name: Sergey Vasilyev + github: s2504s +- name: Michael Pereira + github: MichaelPereira +- name: Jamie Nelson + github: Jamie-BitFlight +- name: Vladimir + github: SweetOps +- name: Daren Desjardins + github: darend +- name: Maarten van der Hoef + github: maartenvanderhoef +- name: Adam Tibbing + github: tibbing diff --git a/.terraform/modules/datadog_integration2.core_label/docs/targets.md b/.terraform/modules/datadog_integration2.core_label/docs/targets.md new file mode 100755 index 0000000..3dce8b3 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/docs/targets.md @@ -0,0 +1,12 @@ + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + diff --git a/.terraform/modules/datadog_integration2.core_label/docs/terraform.md b/.terraform/modules/datadog_integration2.core_label/docs/terraform.md new file mode 100755 index 0000000..d4f48f4 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/docs/terraform.md @@ -0,0 +1,54 @@ + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + diff --git a/.terraform/modules/datadog_integration2.core_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars b/.terraform/modules/datadog_integration2.core_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars new file mode 100755 index 0000000..f7c725f --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars @@ -0,0 +1,12 @@ +namespace = "eg" +stage = "prod" +name = "app" + +tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" +} + +additional_tag_map = { + propagate_at_launch = "true" +} diff --git a/.terraform/modules/datadog_integration2.core_label/examples/autoscalinggroup/context.tf b/.terraform/modules/datadog_integration2.core_label/examples/autoscalinggroup/context.tf new file mode 100755 index 0000000..b97f05f --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/autoscalinggroup/context.tf @@ -0,0 +1,216 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration2.core_label/examples/autoscalinggroup/main.tf b/.terraform/modules/datadog_integration2.core_label/examples/autoscalinggroup/main.tf new file mode 100755 index 0000000..f0d3aa6 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/autoscalinggroup/main.tf @@ -0,0 +1,104 @@ +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + + context = module.this.context +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template { + id = aws_launch_template.default.id + version = "$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} + +################################ +# Provider # +################################ +provider "aws" { + region = "eu-west-1" + + # Make it faster by skipping unneeded checks here + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +############################################################## +# Data sources to get VPC, subnets and security group details +############################################################## +data "aws_vpc" "default" { + default = true +} + +data "aws_subnet_ids" "all" { + vpc_id = data.aws_vpc.default.id +} + +data "aws_security_group" "default" { + vpc_id = data.aws_vpc.default.id + name = "default" +} + +data "aws_ami" "amazon_linux" { + most_recent = true + + owners = ["amazon"] + + filter { + name = "name" + + values = [ + "amzn-ami-hvm-*-x86_64-gp2", + ] + } + + filter { + name = "owner-alias" + + values = [ + "amazon", + ] + } +} + diff --git a/.terraform/modules/datadog_integration2.core_label/examples/autoscalinggroup/outputs.tf b/.terraform/modules/datadog_integration2.core_label/examples/autoscalinggroup/outputs.tf new file mode 100755 index 0000000..f8fcce5 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/autoscalinggroup/outputs.tf @@ -0,0 +1,12 @@ +# terraform-null-label example used here: Output list of tags applied in each format +output "tags_as_list_of_maps" { + value = module.label.tags_as_list_of_maps +} + +output "tags" { + value = module.label.tags +} + +output "id" { + value = module.label.id +} diff --git a/.terraform/modules/datadog_integration2.core_label/examples/autoscalinggroup/versions.tf b/.terraform/modules/datadog_integration2.core_label/examples/autoscalinggroup/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/autoscalinggroup/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration2.core_label/examples/complete/complete.auto.tfvars b/.terraform/modules/datadog_integration2.core_label/examples/complete/complete.auto.tfvars new file mode 100755 index 0000000..e7bc519 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/complete/complete.auto.tfvars @@ -0,0 +1,10 @@ +namespace = "cp" +environment = "uw2" +stage = "prd" +name = "null-label" + +delimiter = "" +id_length_limit = 6 + +label_key_case = "lower" +label_value_case = "upper" diff --git a/.terraform/modules/datadog_integration2.core_label/examples/complete/context.tf b/.terraform/modules/datadog_integration2.core_label/examples/complete/context.tf new file mode 100755 index 0000000..973d4dc --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/complete/context.tf @@ -0,0 +1,217 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration2.core_label/examples/complete/label1.tf b/.terraform/modules/datadog_integration2.core_label/examples/complete/label1.tf new file mode 100755 index 0000000..8da353b --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/complete/label1.tf @@ -0,0 +1,42 @@ +module "label1" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label1" { + value = { + id = module.label1.id + name = module.label1.name + namespace = module.label1.namespace + stage = module.label1.stage + attributes = module.label1.attributes + delimiter = module.label1.delimiter + } +} + +output "label1_tags" { + value = module.label1.tags +} + +output "label1_context" { + value = module.label1.context +} + +output "label1_normalized_context" { + value = module.label1.normalized_context +} + + + diff --git a/.terraform/modules/datadog_integration2.core_label/examples/complete/label1t1.tf b/.terraform/modules/datadog_integration2.core_label/examples/complete/label1t1.tf new file mode 100755 index 0000000..2bcb362 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/complete/label1t1.tf @@ -0,0 +1,18 @@ +module "label1t1" { + source = "../../" + + id_length_limit = 28 + + context = module.label1.context +} + +output "label1t1" { + value = { + id = module.label1t1.id + id_full = module.label1t1.id_full + } +} + +output "label1t1_tags" { + value = module.label1t1.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration2.core_label/examples/complete/label1t2.tf b/.terraform/modules/datadog_integration2.core_label/examples/complete/label1t2.tf new file mode 100755 index 0000000..5df651e --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/complete/label1t2.tf @@ -0,0 +1,18 @@ +module "label1t2" { + source = "../../" + + id_length_limit = 29 + + context = module.label1.context +} + +output "label1t2" { + value = { + id = module.label1t2.id + id_full = module.label1t2.id_full + } +} + +output "label1t2_tags" { + value = module.label1t2.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration2.core_label/examples/complete/label2.tf b/.terraform/modules/datadog_integration2.core_label/examples/complete/label2.tf new file mode 100755 index 0000000..faf7450 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/complete/label2.tf @@ -0,0 +1,42 @@ +module "label2" { + source = "../../" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + regex_replace_chars = "/[^a-zA-Z0-9-+]/" + + additional_tag_map = { + propagate_at_launch = "true" + additional_tag = "yes" + } + + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +output "label2" { + value = { + id = module.label2.id + name = module.label2.name + namespace = module.label2.namespace + stage = module.label2.stage + attributes = module.label2.attributes + delimiter = module.label2.delimiter + } +} + +output "label2_tags" { + value = module.label2.tags +} + +output "label2_tags_as_list_of_maps" { + value = module.label2.tags_as_list_of_maps +} + +output "label2_context" { + value = module.label2.context +} diff --git a/.terraform/modules/datadog_integration2.core_label/examples/complete/label3c.tf b/.terraform/modules/datadog_integration2.core_label/examples/complete/label3c.tf new file mode 100755 index 0000000..338a636 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/complete/label3c.tf @@ -0,0 +1,36 @@ +module "label3c" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3c" { + value = { + id = module.label3c.id + name = module.label3c.name + namespace = module.label3c.namespace + stage = module.label3c.stage + attributes = module.label3c.attributes + delimiter = module.label3c.delimiter + } +} + +output "label3c_tags" { + value = module.label3c.tags +} + +output "label3c_context" { + value = module.label3c.context +} + +output "label3c_normalized_context" { + value = module.label3c.normalized_context +} diff --git a/.terraform/modules/datadog_integration2.core_label/examples/complete/label3n.tf b/.terraform/modules/datadog_integration2.core_label/examples/complete/label3n.tf new file mode 100755 index 0000000..ca51282 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/complete/label3n.tf @@ -0,0 +1,36 @@ +module "label3n" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.normalized_context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3n" { + value = { + id = module.label3n.id + name = module.label3n.name + namespace = module.label3n.namespace + stage = module.label3n.stage + attributes = module.label3n.attributes + delimiter = module.label3n.delimiter + } +} + +output "label3n_tags" { + value = module.label3n.tags +} + +output "label3n_context" { + value = module.label3n.context +} + +output "label3n_normalized_context" { + value = module.label3n.normalized_context +} diff --git a/.terraform/modules/datadog_integration2.core_label/examples/complete/label4.tf b/.terraform/modules/datadog_integration2.core_label/examples/complete/label4.tf new file mode 100755 index 0000000..74e3ca1 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/complete/label4.tf @@ -0,0 +1,34 @@ +module "label4" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + name = "Example Cluster" + attributes = ["big", "fat", "honking", "cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label4" { + value = { + id = module.label4.id + name = module.label4.name + namespace = module.label4.namespace + stage = module.label4.stage + attributes = module.label4.attributes + delimiter = module.label4.delimiter + } +} + +output "label4_tags" { + value = module.label4.tags +} + +output "label4_context" { + value = module.label4.context +} diff --git a/.terraform/modules/datadog_integration2.core_label/examples/complete/label5.tf b/.terraform/modules/datadog_integration2.core_label/examples/complete/label5.tf new file mode 100755 index 0000000..0f0a76e --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/complete/label5.tf @@ -0,0 +1,33 @@ +module "label5" { + source = "../../" + enabled = false + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + } +} + +output "label5" { + value = { + id = module.label5.id + name = module.label5.name + namespace = module.label5.namespace + stage = module.label5.stage + attributes = module.label5.attributes + delimiter = module.label5.delimiter + } +} + +output "label5_tags" { + value = module.label5.tags +} + +output "label5_context" { + value = module.label5.context +} diff --git a/.terraform/modules/datadog_integration2.core_label/examples/complete/label6f.tf b/.terraform/modules/datadog_integration2.core_label/examples/complete/label6f.tf new file mode 100755 index 0000000..1ce1bab --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/complete/label6f.tf @@ -0,0 +1,20 @@ +module "label6f" { + source = "../../" + + delimiter = "~" + id_length_limit = 0 + + # Use values from tfvars + context = module.this.context +} + +output "label6f" { + value = { + id = module.label6f.id + id_full = module.label6f.id_full + } +} + +output "label6f_tags" { + value = module.label6f.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration2.core_label/examples/complete/label6t.tf b/.terraform/modules/datadog_integration2.core_label/examples/complete/label6t.tf new file mode 100755 index 0000000..b5d9bc1 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/complete/label6t.tf @@ -0,0 +1,19 @@ +module "label6t" { + source = "../../" + + # Use values from tfvars, + # specifically: complete.auto.tfvars + context = module.this.context +} + +output "label6t" { + value = { + id = module.label6t.id + id_full = module.label6t.id_full + id_length_limit = module.this.context.id_length_limit + } +} + +output "label6t_tags" { + value = module.label6t.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration2.core_label/examples/complete/label7.tf b/.terraform/modules/datadog_integration2.core_label/examples/complete/label7.tf new file mode 100755 index 0000000..bb365d4 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/complete/label7.tf @@ -0,0 +1,44 @@ +module "label7a" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + } +} + +module "label7" { + source = "../../" + + attributes = ["nodegroup"] + + context = module.label7a.context +} + + +output "label7" { + value = { + id = module.label7.id + name = module.label7.name + namespace = module.label7.namespace + stage = module.label7.stage + attributes = module.label7.attributes + delimiter = module.label7.delimiter + } +} + +output "label7_id" { + value = module.label7.id +} + +output "label7_attributes" { + value = module.label7.attributes +} + +output "label7_context" { + value = module.label7.context +} diff --git a/.terraform/modules/datadog_integration2.core_label/examples/complete/label8d.tf b/.terraform/modules/datadog_integration2.core_label/examples/complete/label8d.tf new file mode 100755 index 0000000..4252419 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/complete/label8d.tf @@ -0,0 +1,44 @@ +module "label8d" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8d_context" { + source = "../../" + + context = module.label8d.context +} + +output "label8d_context_id" { + value = module.label8d_context.id +} + +output "label8d_context_context" { + value = module.label8d_context.context +} + +output "label8d_context_tags" { + value = module.label8d_context.tags +} + +output "label8d_id" { + value = module.label8d.id +} + +output "label8d_context" { + value = module.label8d.context +} + +output "label8d_tags" { + value = module.label8d.tags +} diff --git a/.terraform/modules/datadog_integration2.core_label/examples/complete/label8dcd.tf b/.terraform/modules/datadog_integration2.core_label/examples/complete/label8dcd.tf new file mode 100755 index 0000000..ccdae21 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/complete/label8dcd.tf @@ -0,0 +1,24 @@ +module "label8dcd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "x" +} + +module "label8dcd_context" { + source = "../../" + + context = module.label8dcd.context +} + +output "label8dcd_context_id" { + value = module.label8dcd_context.id +} + +output "label8dcd_id" { + value = module.label8dcd.id +} diff --git a/.terraform/modules/datadog_integration2.core_label/examples/complete/label8dnd.tf b/.terraform/modules/datadog_integration2.core_label/examples/complete/label8dnd.tf new file mode 100755 index 0000000..2edb378 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/complete/label8dnd.tf @@ -0,0 +1,24 @@ +module "label8dnd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "" +} + +module "label8dnd_context" { + source = "../../" + + context = module.label8dnd.context +} + +output "label8dnd_context_id" { + value = module.label8dnd_context.id +} + +output "label8dnd_id" { + value = module.label8dnd.id +} diff --git a/.terraform/modules/datadog_integration2.core_label/examples/complete/label8l.tf b/.terraform/modules/datadog_integration2.core_label/examples/complete/label8l.tf new file mode 100755 index 0000000..7462f9e --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/complete/label8l.tf @@ -0,0 +1,46 @@ +module "label8l" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "lower" + label_value_case = "lower" + + tags = { + "kubernetes.io/cluster/" = "shared" + "upperTEST" = "testUPPER" + } +} + +module "label8l_context" { + source = "../../" + + context = module.label8l.context +} + +output "label8l_context_id" { + value = module.label8l_context.id +} + +output "label8l_context_context" { + value = module.label8l_context.context +} + +output "label8l_context_tags" { + value = module.label8l_context.tags +} + +output "label8l_id" { + value = module.label8l.id +} + +output "label8l_context" { + value = module.label8l.context +} + +output "label8l_tags" { + value = module.label8l.tags +} diff --git a/.terraform/modules/datadog_integration2.core_label/examples/complete/label8n.tf b/.terraform/modules/datadog_integration2.core_label/examples/complete/label8n.tf new file mode 100755 index 0000000..fd4ad57 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/complete/label8n.tf @@ -0,0 +1,45 @@ +module "label8n" { + source = "../../" + + enabled = true + namespace = "EG" + environment = "demo" + name = "blue" + attributes = ["eks", "ClusteR"] + delimiter = "-" + label_value_case = "none" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8n_context" { + source = "../../" + + context = module.label8n.context +} + +output "label8n_context_id" { + value = module.label8n_context.id +} + +output "label8n_context_context" { + value = module.label8n_context.context +} + +output "label8n_context_tags" { + value = module.label8n_context.tags +} + +output "label8n_id" { + value = module.label8n.id +} + +output "label8n_context" { + value = module.label8n.context +} + +output "label8n_tags" { + value = module.label8n.tags +} diff --git a/.terraform/modules/datadog_integration2.core_label/examples/complete/label8t.tf b/.terraform/modules/datadog_integration2.core_label/examples/complete/label8t.tf new file mode 100755 index 0000000..cb54c7a --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/complete/label8t.tf @@ -0,0 +1,45 @@ +module "label8t" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["EKS", "cluster"] + delimiter = "-" + label_key_case = "title" + label_value_case = "title" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8t_context" { + source = "../../" + + context = module.label8t.context +} + +output "label8t_context_id" { + value = module.label8t_context.id +} + +output "label8t_context_context" { + value = module.label8t_context.context +} + +output "label8t_context_tags" { + value = module.label8t_context.tags +} + +output "label8t_id" { + value = module.label8t.id +} + +output "label8t_context" { + value = module.label8t.context +} + +output "label8t_tags" { + value = module.label8t.tags +} diff --git a/.terraform/modules/datadog_integration2.core_label/examples/complete/label8u.tf b/.terraform/modules/datadog_integration2.core_label/examples/complete/label8u.tf new file mode 100755 index 0000000..499535b --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/complete/label8u.tf @@ -0,0 +1,50 @@ +module "label8u" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "upper" + label_value_case = "upper" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8u_context" { + source = "../../" + + context = module.label8u.context +} + +output "label8u_context_id" { + value = module.label8u_context.id +} + +output "label8u_context_context" { + value = module.label8u_context.context +} + +// debug +output "label8u_context_normalized_context" { + value = module.label8u_context.normalized_context +} + +output "label8u_context_tags" { + value = module.label8u_context.tags +} + +output "label8u_id" { + value = module.label8u.id +} + +output "label8u_context" { + value = module.label8u.context +} + +output "label8u_tags" { + value = module.label8u.tags +} diff --git a/.terraform/modules/datadog_integration2.core_label/examples/complete/versions.tf b/.terraform/modules/datadog_integration2.core_label/examples/complete/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/examples/complete/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration2.core_label/exports/context.tf b/.terraform/modules/datadog_integration2.core_label/exports/context.tf new file mode 100755 index 0000000..81f99b4 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/exports/context.tf @@ -0,0 +1,202 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration2.core_label/main.tf b/.terraform/modules/datadog_integration2.core_label/main.tf new file mode 100755 index 0000000..0deda2b --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/main.tf @@ -0,0 +1,146 @@ +locals { + + defaults = { + label_order = ["namespace", "environment", "stage", "name", "attributes"] + regex_replace_chars = "/[^-a-zA-Z0-9]/" + delimiter = "-" + replacement = "" + id_length_limit = 0 + id_hash_length = 5 + label_key_case = "title" + label_value_case = "lower" + } + + # So far, we have decided not to allow overriding replacement or id_hash_length + replacement = local.defaults.replacement + id_hash_length = local.defaults.id_hash_length + + # The values provided by variables supersede the values inherited from the context object, + # except for tags and attributes which are merged. + input = { + # It would be nice to use coalesce here, but we cannot, because it + # is an error for all the arguments to coalesce to be empty. + enabled = var.enabled == null ? var.context.enabled : var.enabled + namespace = var.namespace == null ? var.context.namespace : var.namespace + environment = var.environment == null ? var.context.environment : var.environment + stage = var.stage == null ? var.context.stage : var.stage + name = var.name == null ? var.context.name : var.name + delimiter = var.delimiter == null ? var.context.delimiter : var.delimiter + # modules tack on attributes (passed by var) to the end of the list (passed by context) + attributes = compact(distinct(concat(coalesce(var.context.attributes, []), coalesce(var.attributes, [])))) + tags = merge(var.context.tags, var.tags) + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + label_order = var.label_order == null ? var.context.label_order : var.label_order + regex_replace_chars = var.regex_replace_chars == null ? var.context.regex_replace_chars : var.regex_replace_chars + id_length_limit = var.id_length_limit == null ? var.context.id_length_limit : var.id_length_limit + label_key_case = var.label_key_case == null ? lookup(var.context, "label_key_case", null) : var.label_key_case + label_value_case = var.label_value_case == null ? lookup(var.context, "label_value_case", null) : var.label_value_case + } + + + enabled = local.input.enabled + regex_replace_chars = coalesce(local.input.regex_replace_chars, local.defaults.regex_replace_chars) + + # string_label_names are names of inputs that are strings (not list of strings) used as labels + string_label_names = ["name", "namespace", "environment", "stage"] + normalized_labels = { for k in local.string_label_names : k => + local.input[k] == null ? "" : replace(local.input[k], local.regex_replace_chars, local.replacement) + } + normalized_attributes = compact(distinct([for v in local.input.attributes : replace(v, local.regex_replace_chars, local.replacement)])) + + formatted_labels = { for k in local.string_label_names : k => local.label_value_case == "none" ? local.normalized_labels[k] : + local.label_value_case == "title" ? title(lower(local.normalized_labels[k])) : + local.label_value_case == "upper" ? upper(local.normalized_labels[k]) : lower(local.normalized_labels[k]) + } + + attributes = compact(distinct([ + for v in local.normalized_attributes : (local.label_value_case == "none" ? v : + local.label_value_case == "title" ? title(lower(v)) : + local.label_value_case == "upper" ? upper(v) : lower(v)) + ])) + + name = local.formatted_labels["name"] + namespace = local.formatted_labels["namespace"] + environment = local.formatted_labels["environment"] + stage = local.formatted_labels["stage"] + + delimiter = local.input.delimiter == null ? local.defaults.delimiter : local.input.delimiter + label_order = local.input.label_order == null ? local.defaults.label_order : coalescelist(local.input.label_order, local.defaults.label_order) + id_length_limit = local.input.id_length_limit == null ? local.defaults.id_length_limit : local.input.id_length_limit + label_key_case = local.input.label_key_case == null ? local.defaults.label_key_case : local.input.label_key_case + label_value_case = local.input.label_value_case == null ? local.defaults.label_value_case : local.input.label_value_case + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + + tags = merge(local.generated_tags, local.input.tags) + + tags_as_list_of_maps = flatten([ + for key in keys(local.tags) : merge( + { + key = key + value = local.tags[key] + }, var.additional_tag_map) + ]) + + tags_context = { + # For AWS we need `Name` to be disambiguated since it has a special meaning + name = local.id + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = local.id_context.attributes + } + + generated_tags = { + for l in keys(local.tags_context) : + local.label_key_case == "upper" ? upper(l) : ( + local.label_key_case == "lower" ? lower(l) : title(lower(l)) + ) => local.tags_context[l] if length(local.tags_context[l]) > 0 + } + + id_context = { + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = join(local.delimiter, local.attributes) + } + + labels = [for l in local.label_order : local.id_context[l] if length(local.id_context[l]) > 0] + + id_full = join(local.delimiter, local.labels) + # Create a truncated ID if needed + delimiter_length = length(local.delimiter) + # Calculate length of normal part of ID, leaving room for delimiter and hash + id_truncated_length_limit = local.id_length_limit - (local.id_hash_length + local.delimiter_length) + # Truncate the ID and ensure a single (not double) trailing delimiter + id_truncated = local.id_truncated_length_limit <= 0 ? "" : "${trimsuffix(substr(local.id_full, 0, local.id_truncated_length_limit), local.delimiter)}${local.delimiter}" + # Support usages that disallow numeric characters. Would prefer tr 0-9 q-z but Terraform does not support it. + id_hash_plus = "${md5(local.id_full)}qrstuvwxyz" + id_hash_case = local.label_value_case == "title" ? title(local.id_hash_plus) : local.label_value_case == "upper" ? upper(local.id_hash_plus) : local.label_value_case == "lower" ? lower(local.id_hash_plus) : local.id_hash_plus + id_hash = replace(local.id_hash_case, local.regex_replace_chars, local.replacement) + # Create the short ID by adding a hash to the end of the truncated ID + id_short = substr("${local.id_truncated}${local.id_hash}", 0, local.id_length_limit) + id = local.id_length_limit != 0 && length(local.id_full) > local.id_length_limit ? local.id_short : local.id_full + + + # Context of this label to pass to other label modules + output_context = { + enabled = local.enabled + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + delimiter = local.delimiter + attributes = local.attributes + tags = local.tags + additional_tag_map = local.additional_tag_map + label_order = local.label_order + regex_replace_chars = local.regex_replace_chars + id_length_limit = local.id_length_limit + label_key_case = local.label_key_case + label_value_case = local.label_value_case + } + +} diff --git a/.terraform/modules/datadog_integration2.core_label/outputs.tf b/.terraform/modules/datadog_integration2.core_label/outputs.tf new file mode 100755 index 0000000..87ad1be --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/outputs.tf @@ -0,0 +1,88 @@ +output "id" { + value = local.enabled ? local.id : "" + description = "Disambiguated ID restricted to `id_length_limit` characters in total" +} + +output "id_full" { + value = local.enabled ? local.id_full : "" + description = "Disambiguated ID not restricted in length" +} + +output "enabled" { + value = local.enabled + description = "True if module is enabled, false otherwise" +} + +output "namespace" { + value = local.enabled ? local.namespace : "" + description = "Normalized namespace" +} + +output "environment" { + value = local.enabled ? local.environment : "" + description = "Normalized environment" +} + +output "name" { + value = local.enabled ? local.name : "" + description = "Normalized name" +} + +output "stage" { + value = local.enabled ? local.stage : "" + description = "Normalized stage" +} + +output "delimiter" { + value = local.enabled ? local.delimiter : "" + description = "Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes`" +} + +output "attributes" { + value = local.enabled ? local.attributes : [] + description = "List of attributes" +} + +output "tags" { + value = local.enabled ? local.tags : {} + description = "Normalized Tag map" +} + +output "additional_tag_map" { + value = local.additional_tag_map + description = "The merged additional_tag_map" +} + +output "label_order" { + value = local.label_order + description = "The naming order actually used to create the ID" +} + +output "regex_replace_chars" { + value = local.regex_replace_chars + description = "The regex_replace_chars actually used to create the ID" +} + +output "id_length_limit" { + value = local.id_length_limit + description = "The id_length_limit actually used to create the ID, with `0` meaning unlimited" +} + +output "tags_as_list_of_maps" { + value = local.tags_as_list_of_maps + description = "Additional tags as a list of maps, which can be used in several AWS resources" +} + +output "normalized_context" { + value = local.output_context + description = "Normalized context of this module" +} + +output "context" { + value = local.input + description = <<-EOT + Merged but otherwise unmodified input to this module, to be used as context input to other modules. + Note: this version will have null values as defaults, not the values actually used as defaults. +EOT +} + diff --git a/.terraform/modules/datadog_integration2.core_label/test/Makefile b/.terraform/modules/datadog_integration2.core_label/test/Makefile new file mode 100755 index 0000000..ea15d62 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/test/Makefile @@ -0,0 +1,43 @@ +TEST_HARNESS ?= https://github.com/cloudposse/test-harness.git +TEST_HARNESS_BRANCH ?= master +TEST_HARNESS_PATH = $(realpath .test-harness) +BATS_ARGS ?= --tap +BATS_LOG ?= test.log + +# Define a macro to run the tests +define RUN_TESTS +@echo "Running tests in $(1)" +@cd $(1) && bats $(BATS_ARGS) $(addsuffix .bats,$(addprefix $(TEST_HARNESS_PATH)/test/terraform/,$(TESTS))) +endef + +default: all + +-include Makefile.* + +## Provision the test-harnesss +.test-harness: + [ -d $@ ] || git clone --depth=1 -b $(TEST_HARNESS_BRANCH) $(TEST_HARNESS) $@ + +## Initialize the tests +init: .test-harness + +## Install all dependencies (OS specific) +deps:: + @exit 0 + +## Clean up the test harness +clean: + [ "$(TEST_HARNESS_PATH)" == "/" ] || rm -rf $(TEST_HARNESS_PATH) + +## Run all tests +all: module examples/complete + +## Run basic sanity checks against the module itself +module: export TESTS ?= installed lint get-modules module-pinning get-plugins provider-pinning validate terraform-docs input-descriptions output-descriptions +module: deps + $(call RUN_TESTS, ../) + +## Run tests against example +examples/complete: export TESTS ?= installed lint get-modules get-plugins validate init plan apply +examples/complete: deps + $(call RUN_TESTS, ../$@) diff --git a/.terraform/modules/datadog_integration2.core_label/test/Makefile.alpine b/.terraform/modules/datadog_integration2.core_label/test/Makefile.alpine new file mode 100755 index 0000000..7925b18 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/test/Makefile.alpine @@ -0,0 +1,5 @@ +ifneq (,$(wildcard /sbin/apk)) +## Install all dependencies for alpine +deps:: init + @apk add --update terraform-docs@cloudposse json2hcl@cloudposse +endif diff --git a/.terraform/modules/datadog_integration2.core_label/test/src/Makefile b/.terraform/modules/datadog_integration2.core_label/test/src/Makefile new file mode 100755 index 0000000..b772822 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/test/src/Makefile @@ -0,0 +1,30 @@ +export TF_CLI_ARGS_init ?= -get-plugins=true +export TERRAFORM_VERSION ?= $(shell curl -s https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r -M '.current_version' | cut -d. -f1-2) + +.DEFAULT_GOAL : all +.PHONY: all + +## Default target +all: test + +.PHONY : init +## Initialize tests +init: + @exit 0 + +.PHONY : test +## Run tests +test: init + go mod download + go test -v -timeout 60m -run TestExamplesComplete + +## Run tests in docker container +docker/test: + docker run --name terratest --rm -it -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e GITHUB_TOKEN \ + -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" \ + -v $(CURDIR)/../../:/module/ cloudposse/test-harness:latest -C /module/test/src test + +.PHONY : clean +## Clean up files +clean: + rm -rf ../../examples/complete/*.tfstate* diff --git a/.terraform/modules/datadog_integration2.core_label/test/src/examples_complete_test.go b/.terraform/modules/datadog_integration2.core_label/test/src/examples_complete_test.go new file mode 100755 index 0000000..156e293 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/test/src/examples_complete_test.go @@ -0,0 +1,293 @@ +package test + +import ( + "fmt" + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" + "github.com/qdm12/reprint" + "github.com/stretchr/testify/assert" +) + +type NLContext struct { + AdditionalTagMap map[string]string `json:"additional_tag_map"` + Attributes []string `json:"attributes"` + Delimiter interface{} `json:"delimiter"` + Enabled bool `json:"enabled"` + Environment interface{} `json:"environment"` + LabelOrder []string `json:"label_order"` + Name interface{} `json:"name"` + Namespace interface{} `json:"namespace"` + RegexReplaceChars interface{} `json:"regex_replace_chars"` + Stage interface{} `json:"stage"` + Tags map[string]string `json:"tags"` +} + +// Test the Terraform module in examples/complete using Terratest. +func TestExamplesComplete(t *testing.T) { + t.Parallel() + + terraformOptions := &terraform.Options{ + // The path to where our Terraform code is located + TerraformDir: "../../examples/complete", + Upgrade: true, + } + + // At the end of the test, run `terraform destroy` to clean up any resources that were created + defer terraform.Destroy(t, terraformOptions) + + // This will run `terraform init` and `terraform apply` and fail the test if there are any errors + terraform.InitAndApply(t, terraformOptions) + + expectedLabel1Context := NLContext{ + Enabled: true, + Namespace: "CloudPosse", + Environment: "UAT", + Stage: "build", + Name: "Winston Churchroom", + Attributes: []string{"fire", "water", "earth", "air"}, + Delimiter: "-", + LabelOrder: []string{"name", "environment", "stage", "attributes"}, + Tags: map[string]string{ + "City": "Dublin", + "Environment": "Private", + }, + AdditionalTagMap: map[string]string{}, + } + + var expectedLabel1NormalizedContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel1NormalizedContext) + expectedLabel1NormalizedContext.Namespace = "cloudposse" + expectedLabel1NormalizedContext.Environment = "uat" + expectedLabel1NormalizedContext.Name = "winstonchurchroom" + expectedLabel1NormalizedContext.RegexReplaceChars = "/[^-a-zA-Z0-9]/" + expectedLabel1NormalizedContext.Tags = map[string]string{ + "City": "Dublin", + "Environment": "Private", + "Namespace": "cloudposse", + "Stage": "build", + "Name": "winstonchurchroom-uat-build-fire-water-earth-air", + "Attributes": "fire-water-earth-air", + } + + var label1NormalizedContext, label1Context NLContext + // Run `terraform output` to get the value of an output variable + label1 := terraform.OutputMap(t, terraformOptions, "label1") + label1Tags := terraform.OutputMap(t, terraformOptions, "label1_tags") + terraform.OutputStruct(t, terraformOptions, "label1_normalized_context", &label1NormalizedContext) + terraform.OutputStruct(t, terraformOptions, "label1_context", &label1Context) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1["id"]) + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1Tags["Name"]) + assert.Equal(t, "Dublin", label1Tags["City"]) + assert.Equal(t, "Private", label1Tags["Environment"]) + assert.Equal(t, expectedLabel1NormalizedContext, label1NormalizedContext) + assert.Equal(t, expectedLabel1Context, label1Context) + + label1t1 := terraform.OutputMap(t, terraformOptions, "label1t1") + label1t1Tags := terraform.OutputMap(t, terraformOptions, "label1t1_tags") + assert.Equal(t, "winstonchurchroom-uat-6a0b34", label1t1["id"], + "Extra hash character should be added when trailing delimiter is removed") + assert.Equal(t, label1["id"], label1t1["id_full"], "id_full should not be truncated") + assert.Equal(t, label1t1["id"], label1t1Tags["Name"], "Name tag should match ID") + + label1t2 := terraform.OutputMap(t, terraformOptions, "label1t2") + label1t2Tags := terraform.OutputMap(t, terraformOptions, "label1t2_tags") + assert.Equal(t, "winstonchurchroom-uat-b-6a0b3", label1t2["id"]) + assert.Equal(t, label1t2["id"], label1t2Tags["Name"], "Name tag should match ID") + + // Run `terraform output` to get the value of an output variable + label2 := terraform.OutputMap(t, terraformOptions, "label2") + label2Tags := terraform.OutputMap(t, terraformOptions, "label2_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2["id"]) + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2Tags["Name"]) + assert.Equal(t, "London", label2Tags["City"]) + assert.Equal(t, "Public", label2Tags["Environment"]) + + var expectedLabel3cContext, label3cContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel3cContext) + expectedLabel3cContext.Name = "Starfish" + expectedLabel3cContext.Stage = "release" + expectedLabel3cContext.Delimiter = "." + expectedLabel3cContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3cContext.Tags["Eat"] = "Carrot" + expectedLabel3cContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3c := terraform.OutputMap(t, terraformOptions, "label3c") + label3cTags := terraform.OutputMap(t, terraformOptions, "label3c_tags") + terraform.OutputStruct(t, terraformOptions, "label3c_context", &label3cContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3c["id"]) + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3cTags["Name"]) + assert.Equal(t, expectedLabel3cContext, label3cContext) + + var expectedLabel3nContext, label3nContext NLContext + _ = reprint.FromTo(&expectedLabel1NormalizedContext, &expectedLabel3nContext) + expectedLabel3nContext.Name = "Starfish" + expectedLabel3nContext.Stage = "release" + expectedLabel3nContext.Delimiter = "." + expectedLabel3nContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3nContext.Tags["Eat"] = "Carrot" + expectedLabel3nContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3n := terraform.OutputMap(t, terraformOptions, "label3n") + label3nTags := terraform.OutputMap(t, terraformOptions, "label3n_tags") + terraform.OutputStruct(t, terraformOptions, "label3n_context", &label3nContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3n["id"]) + assert.Equal(t, label1Tags["Name"], label3nTags["Name"], + "Tag from label1 normalized context should overwrite label3n generated tag") + assert.Equal(t, expectedLabel3nContext, label3nContext) + + // Run `terraform output` to get the value of an output variable + label4 := terraform.OutputMap(t, terraformOptions, "label4") + label4Tags := terraform.OutputMap(t, terraformOptions, "label4_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4["id"]) + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4Tags["Name"]) + + // Run `terraform output` to get the value of an output variable + label5 := terraform.OutputMap(t, terraformOptions, "label5") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "", label5["id"]) + + label6f := terraform.OutputMap(t, terraformOptions, "label6f") + label6fTags := terraform.OutputMap(t, terraformOptions, "label6f_tags") + // Test of setting var.label_key_case = "lower", var.label_value_case = "upper" + assert.Equal(t, "CP~UW2~PRD~NULL-LABEL", label6f["id_full"]) + assert.Equal(t, label6f["id_full"], label6f["id"], "id should not be truncated") + assert.Equal(t, label6f["id"], label6fTags["name"], "Name tag should match ID") + + label6t := terraform.OutputMap(t, terraformOptions, "label6t") + label6tTags := terraform.OutputMap(t, terraformOptions, "label6t_tags") + assert.Equal(t, "CPUW2PRDNULL-LABEL", label6t["id_full"]) + assert.NotEqual(t, label6t["id_full"], label6t["id"], "id should be truncated") + assert.Equal(t, label6t["id"], label6tTags["name"], "Name tag should match ID") + assert.Equal(t, label6t["id_length_limit"], fmt.Sprintf("%d", len(label6t["id"])), + "Truncated ID length should equal length limit") + + label7 := terraform.OutputMap(t, terraformOptions, "label7") + assert.Equal(t, "eg-demo-blue-cluster-nodegroup", label7["id"], "var.attributes should be appended after context.attributes") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter=""` returns expected value of id, context id + label8dndID := terraform.Output(t, terraformOptions, "label8dnd_id") + label8dndContextID := terraform.Output(t, terraformOptions, "label8dnd_context_id") + assert.Equal(t, "egdemobluecluster", label8dndID) + assert.Equal(t, label8dndID, label8dndContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter="x"` returns expected value of id, context id + label8dcdID := terraform.Output(t, terraformOptions, "label8dcd_id") + label8dcdContextID := terraform.Output(t, terraformOptions, "label8dcd_context_id") + assert.Equal(t, "egxdemoxbluexcluster", label8dcdID) + assert.Equal(t, label8dcdID, label8dcdContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=lower` returns expected values of id, tags, context tags + label8dExpectedTags := map[string]string{ + "Attributes": "cluster", + "Environment": "demo", + "Name": "eg-demo-blue-cluster", + "Namespace": "eg", + "kubernetes.io/cluster/": "shared", + } + + label8dID := terraform.Output(t, terraformOptions, "label8d_id") + label8dContextID := terraform.Output(t, terraformOptions, "label8d_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8dID) + assert.Equal(t, label8dID, label8dContextID, "ID and context ID should be equal") + + label8dTags := terraform.OutputMap(t, terraformOptions, "label8d_tags") + label8dContextTags := terraform.OutputMap(t, terraformOptions, "label8d_context_tags") + + assert.Exactly(t, label8dExpectedTags, label8dTags, "generated tags are different from expected") + assert.Exactly(t, label8dTags, label8dContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=lower` and `label_value_case=lower` returns expected values of id, tags, context tags + label8lExpectedTags := map[string]string{ + "attributes": "cluster", + "environment": "demo", + "name": "eg-demo-blue-cluster", + "namespace": "eg", + "kubernetes.io/cluster/": "shared", + "upperTEST": "testUPPER", + } + + label8lID := terraform.Output(t, terraformOptions, "label8l_id") + label8lContextID := terraform.Output(t, terraformOptions, "label8l_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8lID) + assert.Equal(t, label8lID, label8lContextID, "ID and context ID should be equal") + + label8lTags := terraform.OutputMap(t, terraformOptions, "label8l_tags") + label8lContextTags := terraform.OutputMap(t, terraformOptions, "label8l_context_tags") + + assert.Exactly(t, label8lExpectedTags, label8lTags, "generated tags are different from expected") + assert.Exactly(t, label8lTags, label8lContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=title` returns expected values of id, tags, context tags + label8tExpectedTags := map[string]string{ + "Attributes": "Eks-Cluster", + "Environment": "Demo", + "Name": "Eg-Demo-Blue-Eks-Cluster", + "Namespace": "Eg", + "kubernetes.io/cluster/": "shared", + } + + label8tID := terraform.Output(t, terraformOptions, "label8t_id") + label8tContextID := terraform.Output(t, terraformOptions, "label8t_context_id") + assert.Equal(t, "Eg-Demo-Blue-Eks-Cluster", label8tID) + assert.Equal(t, label8tID, label8tContextID, "ID and context ID should be equal") + + label8tTags := terraform.OutputMap(t, terraformOptions, "label8t_tags") + label8tContextTags := terraform.OutputMap(t, terraformOptions, "label8t_context_tags") + + assert.Exactly(t, label8tExpectedTags, label8tTags, "generated tags are different from expected") + assert.Exactly(t, label8tTags, label8tContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=upper` and `label_value_case=upper` returns expected values of id, tags, context tags + label8uExpectedTags := map[string]string{ + "ATTRIBUTES": "CLUSTER", + "ENVIRONMENT": "DEMO", + "NAME": "EG-DEMO-BLUE-CLUSTER", + "NAMESPACE": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8uID := terraform.Output(t, terraformOptions, "label8u_id") + label8uContextID := terraform.Output(t, terraformOptions, "label8u_context_id") + assert.Equal(t, "EG-DEMO-BLUE-CLUSTER", label8uID) + assert.Equal(t, label8uID, label8uContextID, "ID and context ID should be equal") + + label8uTags := terraform.OutputMap(t, terraformOptions, "label8u_tags") + label8uContextTags := terraform.OutputMap(t, terraformOptions, "label8u_context_tags") + + assert.Exactly(t, label8uExpectedTags, label8uTags, "generated tags are different from expected") + assert.Exactly(t, label8uTags, label8uContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=none` returns expected values of id, tags, context tags + label8nExpectedTags := map[string]string{ + "Attributes": "eks-ClusteR", + "Environment": "demo", + "Name": "EG-demo-blue-eks-ClusteR", + "Namespace": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8nID := terraform.Output(t, terraformOptions, "label8n_id") + label8nContextID := terraform.Output(t, terraformOptions, "label8n_context_id") + assert.Equal(t, "EG-demo-blue-eks-ClusteR", label8nID) + assert.Equal(t, label8nID, label8nContextID, "ID and context ID should be equal") + + label8nTags := terraform.OutputMap(t, terraformOptions, "label8n_tags") + label8nContextTags := terraform.OutputMap(t, terraformOptions, "label8n_context_tags") + + assert.Exactly(t, label8nExpectedTags, label8nTags, "generated tags are different from expected") + assert.Exactly(t, label8nTags, label8nContextTags, "tags and context tags should be equal") +} diff --git a/.terraform/modules/datadog_integration2.core_label/test/src/go.mod b/.terraform/modules/datadog_integration2.core_label/test/src/go.mod new file mode 100755 index 0000000..d866541 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/test/src/go.mod @@ -0,0 +1,9 @@ +module github.com/cloudposse/terraform-null-label + +go 1.14 + +require ( + github.com/gruntwork-io/terratest v0.31.1 + github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 + github.com/stretchr/testify v1.6.1 +) diff --git a/.terraform/modules/datadog_integration2.core_label/test/src/go.sum b/.terraform/modules/datadog_integration2.core_label/test/src/go.sum new file mode 100755 index 0000000..b8d46b1 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/test/src/go.sum @@ -0,0 +1,595 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= +github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.5/go.mod h1:foo3aIXRQ90zFve3r0QiDsrjGDUwWhKl0ZOQy1CT14k= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= +github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200109221225-a4f60165b7a3/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= +github.com/gruntwork-io/terratest v0.31.1 h1:MPGe/5pGgJAIZ/hb+0LM1KyJKSi/QyxSkHoP9/CBhJg= +github.com/gruntwork-io/terratest v0.31.1/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= +github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4= +github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= +github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= +k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= +k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= +k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= +k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= +k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= +k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= +k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= +modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/.terraform/modules/datadog_integration2.core_label/variables.tf b/.terraform/modules/datadog_integration2.core_label/variables.tf new file mode 100755 index 0000000..40fb268 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/variables.tf @@ -0,0 +1,157 @@ +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} diff --git a/.terraform/modules/datadog_integration2.core_label/versions.tf b/.terraform/modules/datadog_integration2.core_label/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration2.core_label/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds b/.terraform/modules/datadog_integration2.forwarder_rds new file mode 160000 index 0000000..6f24262 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds @@ -0,0 +1 @@ +Subproject commit 6f24262652a52a055de711cfee0e3dfac5221e0e diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/LICENSE b/.terraform/modules/datadog_integration2.forwarder_rds.this/LICENSE new file mode 100755 index 0000000..c844c70 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017-2020 Cloud Posse, LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/Makefile b/.terraform/modules/datadog_integration2.forwarder_rds.this/Makefile new file mode 100755 index 0000000..97d8087 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/Makefile @@ -0,0 +1,10 @@ +SHELL := /bin/bash + +# List of targets the `readme` target should call before generating the readme +export README_DEPS ?= docs/targets.md docs/terraform.md + +-include $(shell curl -sSL -o .build-harness "https://git.io/build-harness"; echo .build-harness) + +## Lint terraform code +lint: + $(SELF) terraform/install terraform/get-modules terraform/get-plugins terraform/lint terraform/validate diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/README.md b/.terraform/modules/datadog_integration2.forwarder_rds.this/README.md new file mode 100755 index 0000000..32950e4 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/README.md @@ -0,0 +1,938 @@ + +# terraform-null-label [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-null-label.svg)](https://github.com/cloudposse/terraform-null-label/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) + + +[![README Header][readme_header_img]][readme_header_link] + +[![Cloud Posse][logo]](https://cpco.io/homepage) + + + +Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + +This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. +However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). +So if you prefer the term `stage` to `environment` +you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. +- If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. +- If you want the attributes in a different order, you can specify that, too, with the `label_order` list. +- You can set a maximum length for the name, and the module will create a unique name that fits within that length. +- You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. +- The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + +It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. +For example, if you have 10 instances, there should be 10 different labels. +However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + +All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + +**NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. +With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + +- Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. +- Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. +- Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. + + +--- + +This project is part of our comprehensive ["SweetOps"](https://cpco.io/sweetops) approach towards DevOps. +[][share_email] +[][share_googleplus] +[][share_facebook] +[][share_reddit] +[][share_linkedin] +[][share_twitter] + + +[![Terraform Open Source Modules](https://docs.cloudposse.com/images/terraform-open-source-modules.svg)][terraform_modules] + + + +It's 100% Open Source and licensed under the [APACHE2](LICENSE). + + + + + + + +We literally have [*hundreds of terraform modules*][terraform_modules] that are Open Source and well-maintained. Check them out! + + + + + + + +## Security & Compliance [](https://bridgecrew.io/) + +Security scanning is graciously provided by Bridgecrew. Bridgecrew is the leading fully hosted, cloud-native solution providing continuous Terraform security and compliance. + +| Benchmark | Description | +|--------|---------------| +| [![Infrastructure Security](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/general)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=INFRASTRUCTURE+SECURITY) | Infrastructure Security Compliance | +| [![CIS KUBERNETES](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_kubernetes)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+KUBERNETES+V1.5) | Center for Internet Security, KUBERNETES Compliance | +| [![CIS AWS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_aws)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AWS+V1.2) | Center for Internet Security, AWS Compliance | +| [![CIS AZURE](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_azure)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AZURE+V1.1) | Center for Internet Security, AZURE Compliance | +| [![PCI-DSS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/pci)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=PCI-DSS+V3.2) | Payment Card Industry Data Security Standards Compliance | +| [![NIST-800-53](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/nist)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=NIST-800-53) | National Institute of Standards and Technology Compliance | +| [![ISO27001](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/iso)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=ISO27001) | Information Security Management System, ISO/IEC 27001 Compliance | +| [![SOC2](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/soc2)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=SOC2)| Service Organization Control 2 Compliance | +| [![CIS GCP](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_gcp)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+GCP+V1.1) | Center for Internet Security, GCP Compliance | +| [![HIPAA](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/hipaa)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=HIPAA) | Health Insurance Portability and Accountability Compliance | + + + +## Usage + + +**IMPORTANT:** We do not pin modules to versions in our examples because of the +difficulty of keeping the versions in the documentation in sync with the latest released versions. +We highly recommend that in your code you pin the version to the exact version you are +using so that your infrastructure remains stable, and update versions in a +systematic way so that they do not catch you by surprise. + +Also, because of a bug in the Terraform registry ([hashicorp/terraform#21417](https://github.com/hashicorp/terraform/issues/21417)), +the registry shows many of our inputs as required when in fact they are optional. +The table below correctly indicates which inputs are required. + + +### Defaults + +Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. +The context object is a single object that contains all the input values for `terraform-null-label`. +However, each input value can also be specified individually by name as a standard Terraform variable, +and the value of those variables, when set to something other than `null`, will override the value +in the context object. In order to allow chaining of these objects, where the context object input to one +module is transformed and passed to the next module, all the variables default to `null` or empty collections. +The actual default values used when nothing is explicitly set are describe in the documentation below. + +For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, +`terraform-null-label` will actually use the default delimiter `-` (hyphen). + +A non-obvious but intentional consequence of this design is that once a module sets a non-default value, +future modules in the chain cannot reset the value back to the original default. Insted, the new setting +becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, +so once a tag is added, it will remain in the tag set and cannot be removed, although its value can +be overwritten. + +### Simple Example + +```hcl +module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} +``` + +This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` +(you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + +Now reference the label when creating an instance: + +```hcl +resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags +} +``` + +Or define a security group: + +```hcl +resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} +``` + + +### Advanced Example + +Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + +```hcl +module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] +} + +module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] +} +``` + +
+ +### Advanced Example 2 + +Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + +```hcl +tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } +] +``` + +Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + +```hcl +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} +``` + +
+ +### Advanced Example 3 + +See [complete example](./examples/complete) for even more examples. + +This example shows how you can pass the `context` output of one label module to the next label_module, +allowing you to create one label that has the base set of values, and then creating every extra label +as a derivative of that. + +
Click to show + +```hcl +module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} +``` + +This creates label outputs like this: + +```hcl +label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" +} +label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } +} +label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } +} +label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" +} +label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" +} +label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } +} +label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" +} +label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, +] +label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" +} +label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } +} +label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } +} +label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" +} + +``` + +
+ + + + + + + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + + + + +## Share the Love + +Like this project? Please give it a ★ on [our GitHub](https://github.com/cloudposse/terraform-null-label)! (it helps us **a lot**) + +Are you using this project or any of our other projects? Consider [leaving a testimonial][testimonial]. =) + + +## Related Projects + +Check out these related projects. + +- [terraform-terraform-label](https://github.com/cloudposse/terraform-terraform-label) - Terraform Module to define a consistent naming convention by (namespace, environment, stage, name, [attributes]) + + + +## Help + +**Got a question?** We got answers. + +File a GitHub [issue](https://github.com/cloudposse/terraform-null-label/issues), send us an [email][email] or join our [Slack Community][slack]. + +[![README Commercial Support][readme_commercial_support_img]][readme_commercial_support_link] + +## DevOps Accelerator for Startups + + +We are a [**DevOps Accelerator**][commercial_support]. We'll help you build your cloud infrastructure from the ground up so you can own it. Then we'll show you how to operate it and stick around for as long as you need us. + +[![Learn More](https://img.shields.io/badge/learn%20more-success.svg?style=for-the-badge)][commercial_support] + +Work directly with our team of DevOps experts via email, slack, and video conferencing. + +We deliver 10x the value for a fraction of the cost of a full-time engineer. Our track record is not even funny. If you want things done right and you need it done FAST, then we're your best bet. + +- **Reference Architecture.** You'll get everything you need from the ground up built using 100% infrastructure as code. +- **Release Engineering.** You'll have end-to-end CI/CD with unlimited staging environments. +- **Site Reliability Engineering.** You'll have total visibility into your apps and microservices. +- **Security Baseline.** You'll have built-in governance with accountability and audit logs for all changes. +- **GitOps.** You'll be able to operate your infrastructure via Pull Requests. +- **Training.** You'll receive hands-on training so your team can operate what we build. +- **Questions.** You'll have a direct line of communication between our teams via a Shared Slack channel. +- **Troubleshooting.** You'll get help to triage when things aren't working. +- **Code Reviews.** You'll receive constructive feedback on Pull Requests. +- **Bug Fixes.** We'll rapidly work with you to fix any bugs in our projects. + +## Slack Community + +Join our [Open Source Community][slack] on Slack. It's **FREE** for everyone! Our "SweetOps" community is where you get to talk with others who share a similar vision for how to rollout and manage infrastructure. This is the best place to talk shop, ask questions, solicit feedback, and work together as a community to build totally *sweet* infrastructure. + +## Discourse Forums + +Participate in our [Discourse Forums][discourse]. Here you'll find answers to commonly asked questions. Most questions will be related to the enormous number of projects we support on our GitHub. Come here to collaborate on answers, find solutions, and get ideas about the products and services we value. It only takes a minute to get started! Just sign in with SSO using your GitHub account. + +## Newsletter + +Sign up for [our newsletter][newsletter] that covers everything on our technology radar. Receive updates on what we're up to on GitHub as well as awesome new projects we discover. + +## Office Hours + +[Join us every Wednesday via Zoom][office_hours] for our weekly "Lunch & Learn" sessions. It's **FREE** for everyone! + +[![zoom](https://img.cloudposse.com/fit-in/200x200/https://cloudposse.com/wp-content/uploads/2019/08/Powered-by-Zoom.png")][office_hours] + +## Contributing + +### Bug Reports & Feature Requests + +Please use the [issue tracker](https://github.com/cloudposse/terraform-null-label/issues) to report any bugs or file feature requests. + +### Developing + +If you are interested in being a contributor and want to get involved in developing this project or [help out](https://cpco.io/help-out) with our other projects, we would love to hear from you! Shoot us an [email][email]. + +In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. + + 1. **Fork** the repo on GitHub + 2. **Clone** the project to your own machine + 3. **Commit** changes to your own branch + 4. **Push** your work back up to your fork + 5. Submit a **Pull Request** so that we can review your changes + +**NOTE:** Be sure to merge the latest changes from "upstream" before making a pull request! + + +## Copyright + +Copyright © 2017-2021 [Cloud Posse, LLC](https://cpco.io/copyright) + + + +## License + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +See [LICENSE](LICENSE) for full details. + +```text +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +``` + + + + + + + + + +## Trademarks + +All other trademarks referenced herein are the property of their respective owners. + +## About + +This project is maintained and funded by [Cloud Posse, LLC][website]. Like it? Please let us know by [leaving a testimonial][testimonial]! + +[![Cloud Posse][logo]][website] + +We're a [DevOps Professional Services][hire] company based in Los Angeles, CA. We ❤️ [Open Source Software][we_love_open_source]. + +We offer [paid support][commercial_support] on all of our projects. + +Check out [our other projects][github], [follow us on twitter][twitter], [apply for a job][jobs], or [hire us][hire] to help with your cloud strategy and implementation. + + + +### Contributors + + +| [![Erik Osterman][osterman_avatar]][osterman_homepage]
[Erik Osterman][osterman_homepage] | [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]
[Andriy Knysh][aknysh_homepage] | [![Igor Rodionov][goruha_avatar]][goruha_homepage]
[Igor Rodionov][goruha_homepage] | [![Sergey Vasilyev][s2504s_avatar]][s2504s_homepage]
[Sergey Vasilyev][s2504s_homepage] | [![Michael Pereira][MichaelPereira_avatar]][MichaelPereira_homepage]
[Michael Pereira][MichaelPereira_homepage] | [![Jamie Nelson][Jamie-BitFlight_avatar]][Jamie-BitFlight_homepage]
[Jamie Nelson][Jamie-BitFlight_homepage] | [![Vladimir][SweetOps_avatar]][SweetOps_homepage]
[Vladimir][SweetOps_homepage] | [![Daren Desjardins][darend_avatar]][darend_homepage]
[Daren Desjardins][darend_homepage] | [![Maarten van der Hoef][maartenvanderhoef_avatar]][maartenvanderhoef_homepage]
[Maarten van der Hoef][maartenvanderhoef_homepage] | [![Adam Tibbing][tibbing_avatar]][tibbing_homepage]
[Adam Tibbing][tibbing_homepage] | +|---|---|---|---|---|---|---|---|---|---| + + + [osterman_homepage]: https://github.com/osterman + [osterman_avatar]: https://img.cloudposse.com/150x150/https://github.com/osterman.png + [aknysh_homepage]: https://github.com/aknysh + [aknysh_avatar]: https://img.cloudposse.com/150x150/https://github.com/aknysh.png + [goruha_homepage]: https://github.com/goruha + [goruha_avatar]: https://img.cloudposse.com/150x150/https://github.com/goruha.png + [s2504s_homepage]: https://github.com/s2504s + [s2504s_avatar]: https://img.cloudposse.com/150x150/https://github.com/s2504s.png + [MichaelPereira_homepage]: https://github.com/MichaelPereira + [MichaelPereira_avatar]: https://img.cloudposse.com/150x150/https://github.com/MichaelPereira.png + [Jamie-BitFlight_homepage]: https://github.com/Jamie-BitFlight + [Jamie-BitFlight_avatar]: https://img.cloudposse.com/150x150/https://github.com/Jamie-BitFlight.png + [SweetOps_homepage]: https://github.com/SweetOps + [SweetOps_avatar]: https://img.cloudposse.com/150x150/https://github.com/SweetOps.png + [darend_homepage]: https://github.com/darend + [darend_avatar]: https://img.cloudposse.com/150x150/https://github.com/darend.png + [maartenvanderhoef_homepage]: https://github.com/maartenvanderhoef + [maartenvanderhoef_avatar]: https://img.cloudposse.com/150x150/https://github.com/maartenvanderhoef.png + [tibbing_homepage]: https://github.com/tibbing + [tibbing_avatar]: https://img.cloudposse.com/150x150/https://github.com/tibbing.png + +[![README Footer][readme_footer_img]][readme_footer_link] +[![Beacon][beacon]][website] + + [logo]: https://cloudposse.com/logo-300x69.svg + [docs]: https://cpco.io/docs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=docs + [website]: https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=website + [github]: https://cpco.io/github?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=github + [jobs]: https://cpco.io/jobs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=jobs + [hire]: https://cpco.io/hire?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=hire + [slack]: https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=slack + [linkedin]: https://cpco.io/linkedin?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=linkedin + [twitter]: https://cpco.io/twitter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=twitter + [testimonial]: https://cpco.io/leave-testimonial?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=testimonial + [office_hours]: https://cloudposse.com/office-hours?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=office_hours + [newsletter]: https://cpco.io/newsletter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=newsletter + [discourse]: https://ask.sweetops.com/?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=discourse + [email]: https://cpco.io/email?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=email + [commercial_support]: https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=commercial_support + [we_love_open_source]: https://cpco.io/we-love-open-source?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=we_love_open_source + [terraform_modules]: https://cpco.io/terraform-modules?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=terraform_modules + [readme_header_img]: https://cloudposse.com/readme/header/img + [readme_header_link]: https://cloudposse.com/readme/header/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_header_link + [readme_footer_img]: https://cloudposse.com/readme/footer/img + [readme_footer_link]: https://cloudposse.com/readme/footer/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_footer_link + [readme_commercial_support_img]: https://cloudposse.com/readme/commercial-support/img + [readme_commercial_support_link]: https://cloudposse.com/readme/commercial-support/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_commercial_support_link + [share_twitter]: https://twitter.com/intent/tweet/?text=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_linkedin]: https://www.linkedin.com/shareArticle?mini=true&title=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_reddit]: https://reddit.com/submit/?url=https://github.com/cloudposse/terraform-null-label + [share_facebook]: https://facebook.com/sharer/sharer.php?u=https://github.com/cloudposse/terraform-null-label + [share_googleplus]: https://plus.google.com/share?url=https://github.com/cloudposse/terraform-null-label + [share_email]: mailto:?subject=terraform-null-label&body=https://github.com/cloudposse/terraform-null-label + [beacon]: https://ga-beacon.cloudposse.com/UA-76589703-4/cloudposse/terraform-null-label?pixel&cs=github&cm=readme&an=terraform-null-label diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/README.yaml b/.terraform/modules/datadog_integration2.forwarder_rds.this/README.yaml new file mode 100755 index 0000000..42bdb84 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/README.yaml @@ -0,0 +1,618 @@ +name: terraform-null-label +tags: +- aws +- terraform +- terraform-modules +- naming-convention +- name +- namespace +- stage +categories: +- terraform-modules/supported +license: APACHE2 +github_repo: cloudposse/terraform-null-label +badges: +- name: Latest Release + image: https://img.shields.io/github/release/cloudposse/terraform-null-label.svg + url: https://github.com/cloudposse/terraform-null-label/releases/latest +- name: Slack Community + image: https://slack.cloudposse.com/badge.svg + url: https://slack.cloudposse.com +related: +- name: terraform-terraform-label + description: Terraform Module to define a consistent naming convention by (namespace, + environment, stage, name, [attributes]) + url: https://github.com/cloudposse/terraform-terraform-label +description: |- + Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + + This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. + However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). + So if you prefer the term `stage` to `environment` + you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. + - If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. + - If you want the attributes in a different order, you can specify that, too, with the `label_order` list. + - You can set a maximum length for the name, and the module will create a unique name that fits within that length. + - You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. + - The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + + It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. + For example, if you have 10 instances, there should be 10 different labels. + However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + + All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + + **NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. + With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + + - Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. + - Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. + - Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. +usage: |- + ### Defaults + + Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. + The context object is a single object that contains all the input values for `terraform-null-label`. + However, each input value can also be specified individually by name as a standard Terraform variable, + and the value of those variables, when set to something other than `null`, will override the value + in the context object. In order to allow chaining of these objects, where the context object input to one + module is transformed and passed to the next module, all the variables default to `null` or empty collections. + The actual default values used when nothing is explicitly set are describe in the documentation below. + + For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, + `terraform-null-label` will actually use the default delimiter `-` (hyphen). + + A non-obvious but intentional consequence of this design is that once a module sets a non-default value, + future modules in the chain cannot reset the value back to the original default. Insted, the new setting + becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, + so once a tag is added, it will remain in the tag set and cannot be removed, although its value can + be overwritten. + + ### Simple Example + + ```hcl + module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + ``` + + This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` + (you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + + Now reference the label when creating an instance: + + ```hcl + resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags + } + ``` + + Or define a security group: + + ```hcl + resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + } + ``` + + + ### Advanced Example + + Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + + ```hcl + module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] + } + + module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] + } + ``` + +
+ + ### Advanced Example 2 + + Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + + ```hcl + tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } + ] + ``` + + Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + + ```hcl + ################################ + # terraform-null-label example # + ################################ + module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } + } + + ####################### + # Launch template # + ####################### + resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } + } + + ###################### + # Autoscaling group # + ###################### + resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps + } + ``` + +
+ + ### Advanced Example 3 + + See [complete example](./examples/complete) for even more examples. + + This example shows how you can pass the `context` output of one label module to the next label_module, + allowing you to create one label that has the base set of values, and then creating every extra label + as a derivative of that. + +
Click to show + + ```hcl + module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } + } + + module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } + } + + module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } + } + ``` + + This creates label outputs like this: + + ```hcl + label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" + } + label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } + } + label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + } + label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" + } + label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } + } + label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" + } + label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, + ] + label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" + } + label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } + } + label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + } + label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + + ``` + +
+ +include: +- docs/targets.md +- docs/terraform.md +contributors: +- name: Erik Osterman + github: osterman +- name: Andriy Knysh + github: aknysh +- name: Igor Rodionov + github: goruha +- name: Sergey Vasilyev + github: s2504s +- name: Michael Pereira + github: MichaelPereira +- name: Jamie Nelson + github: Jamie-BitFlight +- name: Vladimir + github: SweetOps +- name: Daren Desjardins + github: darend +- name: Maarten van der Hoef + github: maartenvanderhoef +- name: Adam Tibbing + github: tibbing diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/docs/targets.md b/.terraform/modules/datadog_integration2.forwarder_rds.this/docs/targets.md new file mode 100755 index 0000000..3dce8b3 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/docs/targets.md @@ -0,0 +1,12 @@ + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/docs/terraform.md b/.terraform/modules/datadog_integration2.forwarder_rds.this/docs/terraform.md new file mode 100755 index 0000000..d4f48f4 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/docs/terraform.md @@ -0,0 +1,54 @@ + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars new file mode 100755 index 0000000..f7c725f --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars @@ -0,0 +1,12 @@ +namespace = "eg" +stage = "prod" +name = "app" + +tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" +} + +additional_tag_map = { + propagate_at_launch = "true" +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/autoscalinggroup/context.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/autoscalinggroup/context.tf new file mode 100755 index 0000000..b97f05f --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/autoscalinggroup/context.tf @@ -0,0 +1,216 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/autoscalinggroup/main.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/autoscalinggroup/main.tf new file mode 100755 index 0000000..f0d3aa6 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/autoscalinggroup/main.tf @@ -0,0 +1,104 @@ +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + + context = module.this.context +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template { + id = aws_launch_template.default.id + version = "$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} + +################################ +# Provider # +################################ +provider "aws" { + region = "eu-west-1" + + # Make it faster by skipping unneeded checks here + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +############################################################## +# Data sources to get VPC, subnets and security group details +############################################################## +data "aws_vpc" "default" { + default = true +} + +data "aws_subnet_ids" "all" { + vpc_id = data.aws_vpc.default.id +} + +data "aws_security_group" "default" { + vpc_id = data.aws_vpc.default.id + name = "default" +} + +data "aws_ami" "amazon_linux" { + most_recent = true + + owners = ["amazon"] + + filter { + name = "name" + + values = [ + "amzn-ami-hvm-*-x86_64-gp2", + ] + } + + filter { + name = "owner-alias" + + values = [ + "amazon", + ] + } +} + diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/autoscalinggroup/outputs.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/autoscalinggroup/outputs.tf new file mode 100755 index 0000000..f8fcce5 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/autoscalinggroup/outputs.tf @@ -0,0 +1,12 @@ +# terraform-null-label example used here: Output list of tags applied in each format +output "tags_as_list_of_maps" { + value = module.label.tags_as_list_of_maps +} + +output "tags" { + value = module.label.tags +} + +output "id" { + value = module.label.id +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/autoscalinggroup/versions.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/autoscalinggroup/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/autoscalinggroup/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/complete.auto.tfvars b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/complete.auto.tfvars new file mode 100755 index 0000000..e7bc519 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/complete.auto.tfvars @@ -0,0 +1,10 @@ +namespace = "cp" +environment = "uw2" +stage = "prd" +name = "null-label" + +delimiter = "" +id_length_limit = 6 + +label_key_case = "lower" +label_value_case = "upper" diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/context.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/context.tf new file mode 100755 index 0000000..973d4dc --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/context.tf @@ -0,0 +1,217 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label1.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label1.tf new file mode 100755 index 0000000..8da353b --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label1.tf @@ -0,0 +1,42 @@ +module "label1" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label1" { + value = { + id = module.label1.id + name = module.label1.name + namespace = module.label1.namespace + stage = module.label1.stage + attributes = module.label1.attributes + delimiter = module.label1.delimiter + } +} + +output "label1_tags" { + value = module.label1.tags +} + +output "label1_context" { + value = module.label1.context +} + +output "label1_normalized_context" { + value = module.label1.normalized_context +} + + + diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label1t1.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label1t1.tf new file mode 100755 index 0000000..2bcb362 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label1t1.tf @@ -0,0 +1,18 @@ +module "label1t1" { + source = "../../" + + id_length_limit = 28 + + context = module.label1.context +} + +output "label1t1" { + value = { + id = module.label1t1.id + id_full = module.label1t1.id_full + } +} + +output "label1t1_tags" { + value = module.label1t1.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label1t2.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label1t2.tf new file mode 100755 index 0000000..5df651e --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label1t2.tf @@ -0,0 +1,18 @@ +module "label1t2" { + source = "../../" + + id_length_limit = 29 + + context = module.label1.context +} + +output "label1t2" { + value = { + id = module.label1t2.id + id_full = module.label1t2.id_full + } +} + +output "label1t2_tags" { + value = module.label1t2.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label2.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label2.tf new file mode 100755 index 0000000..faf7450 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label2.tf @@ -0,0 +1,42 @@ +module "label2" { + source = "../../" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + regex_replace_chars = "/[^a-zA-Z0-9-+]/" + + additional_tag_map = { + propagate_at_launch = "true" + additional_tag = "yes" + } + + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +output "label2" { + value = { + id = module.label2.id + name = module.label2.name + namespace = module.label2.namespace + stage = module.label2.stage + attributes = module.label2.attributes + delimiter = module.label2.delimiter + } +} + +output "label2_tags" { + value = module.label2.tags +} + +output "label2_tags_as_list_of_maps" { + value = module.label2.tags_as_list_of_maps +} + +output "label2_context" { + value = module.label2.context +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label3c.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label3c.tf new file mode 100755 index 0000000..338a636 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label3c.tf @@ -0,0 +1,36 @@ +module "label3c" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3c" { + value = { + id = module.label3c.id + name = module.label3c.name + namespace = module.label3c.namespace + stage = module.label3c.stage + attributes = module.label3c.attributes + delimiter = module.label3c.delimiter + } +} + +output "label3c_tags" { + value = module.label3c.tags +} + +output "label3c_context" { + value = module.label3c.context +} + +output "label3c_normalized_context" { + value = module.label3c.normalized_context +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label3n.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label3n.tf new file mode 100755 index 0000000..ca51282 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label3n.tf @@ -0,0 +1,36 @@ +module "label3n" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.normalized_context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3n" { + value = { + id = module.label3n.id + name = module.label3n.name + namespace = module.label3n.namespace + stage = module.label3n.stage + attributes = module.label3n.attributes + delimiter = module.label3n.delimiter + } +} + +output "label3n_tags" { + value = module.label3n.tags +} + +output "label3n_context" { + value = module.label3n.context +} + +output "label3n_normalized_context" { + value = module.label3n.normalized_context +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label4.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label4.tf new file mode 100755 index 0000000..74e3ca1 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label4.tf @@ -0,0 +1,34 @@ +module "label4" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + name = "Example Cluster" + attributes = ["big", "fat", "honking", "cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label4" { + value = { + id = module.label4.id + name = module.label4.name + namespace = module.label4.namespace + stage = module.label4.stage + attributes = module.label4.attributes + delimiter = module.label4.delimiter + } +} + +output "label4_tags" { + value = module.label4.tags +} + +output "label4_context" { + value = module.label4.context +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label5.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label5.tf new file mode 100755 index 0000000..0f0a76e --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label5.tf @@ -0,0 +1,33 @@ +module "label5" { + source = "../../" + enabled = false + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + } +} + +output "label5" { + value = { + id = module.label5.id + name = module.label5.name + namespace = module.label5.namespace + stage = module.label5.stage + attributes = module.label5.attributes + delimiter = module.label5.delimiter + } +} + +output "label5_tags" { + value = module.label5.tags +} + +output "label5_context" { + value = module.label5.context +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label6f.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label6f.tf new file mode 100755 index 0000000..1ce1bab --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label6f.tf @@ -0,0 +1,20 @@ +module "label6f" { + source = "../../" + + delimiter = "~" + id_length_limit = 0 + + # Use values from tfvars + context = module.this.context +} + +output "label6f" { + value = { + id = module.label6f.id + id_full = module.label6f.id_full + } +} + +output "label6f_tags" { + value = module.label6f.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label6t.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label6t.tf new file mode 100755 index 0000000..b5d9bc1 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label6t.tf @@ -0,0 +1,19 @@ +module "label6t" { + source = "../../" + + # Use values from tfvars, + # specifically: complete.auto.tfvars + context = module.this.context +} + +output "label6t" { + value = { + id = module.label6t.id + id_full = module.label6t.id_full + id_length_limit = module.this.context.id_length_limit + } +} + +output "label6t_tags" { + value = module.label6t.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label7.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label7.tf new file mode 100755 index 0000000..bb365d4 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label7.tf @@ -0,0 +1,44 @@ +module "label7a" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + } +} + +module "label7" { + source = "../../" + + attributes = ["nodegroup"] + + context = module.label7a.context +} + + +output "label7" { + value = { + id = module.label7.id + name = module.label7.name + namespace = module.label7.namespace + stage = module.label7.stage + attributes = module.label7.attributes + delimiter = module.label7.delimiter + } +} + +output "label7_id" { + value = module.label7.id +} + +output "label7_attributes" { + value = module.label7.attributes +} + +output "label7_context" { + value = module.label7.context +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label8d.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label8d.tf new file mode 100755 index 0000000..4252419 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label8d.tf @@ -0,0 +1,44 @@ +module "label8d" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8d_context" { + source = "../../" + + context = module.label8d.context +} + +output "label8d_context_id" { + value = module.label8d_context.id +} + +output "label8d_context_context" { + value = module.label8d_context.context +} + +output "label8d_context_tags" { + value = module.label8d_context.tags +} + +output "label8d_id" { + value = module.label8d.id +} + +output "label8d_context" { + value = module.label8d.context +} + +output "label8d_tags" { + value = module.label8d.tags +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label8dcd.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label8dcd.tf new file mode 100755 index 0000000..ccdae21 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label8dcd.tf @@ -0,0 +1,24 @@ +module "label8dcd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "x" +} + +module "label8dcd_context" { + source = "../../" + + context = module.label8dcd.context +} + +output "label8dcd_context_id" { + value = module.label8dcd_context.id +} + +output "label8dcd_id" { + value = module.label8dcd.id +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label8dnd.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label8dnd.tf new file mode 100755 index 0000000..2edb378 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label8dnd.tf @@ -0,0 +1,24 @@ +module "label8dnd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "" +} + +module "label8dnd_context" { + source = "../../" + + context = module.label8dnd.context +} + +output "label8dnd_context_id" { + value = module.label8dnd_context.id +} + +output "label8dnd_id" { + value = module.label8dnd.id +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label8l.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label8l.tf new file mode 100755 index 0000000..7462f9e --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label8l.tf @@ -0,0 +1,46 @@ +module "label8l" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "lower" + label_value_case = "lower" + + tags = { + "kubernetes.io/cluster/" = "shared" + "upperTEST" = "testUPPER" + } +} + +module "label8l_context" { + source = "../../" + + context = module.label8l.context +} + +output "label8l_context_id" { + value = module.label8l_context.id +} + +output "label8l_context_context" { + value = module.label8l_context.context +} + +output "label8l_context_tags" { + value = module.label8l_context.tags +} + +output "label8l_id" { + value = module.label8l.id +} + +output "label8l_context" { + value = module.label8l.context +} + +output "label8l_tags" { + value = module.label8l.tags +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label8n.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label8n.tf new file mode 100755 index 0000000..fd4ad57 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label8n.tf @@ -0,0 +1,45 @@ +module "label8n" { + source = "../../" + + enabled = true + namespace = "EG" + environment = "demo" + name = "blue" + attributes = ["eks", "ClusteR"] + delimiter = "-" + label_value_case = "none" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8n_context" { + source = "../../" + + context = module.label8n.context +} + +output "label8n_context_id" { + value = module.label8n_context.id +} + +output "label8n_context_context" { + value = module.label8n_context.context +} + +output "label8n_context_tags" { + value = module.label8n_context.tags +} + +output "label8n_id" { + value = module.label8n.id +} + +output "label8n_context" { + value = module.label8n.context +} + +output "label8n_tags" { + value = module.label8n.tags +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label8t.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label8t.tf new file mode 100755 index 0000000..cb54c7a --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label8t.tf @@ -0,0 +1,45 @@ +module "label8t" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["EKS", "cluster"] + delimiter = "-" + label_key_case = "title" + label_value_case = "title" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8t_context" { + source = "../../" + + context = module.label8t.context +} + +output "label8t_context_id" { + value = module.label8t_context.id +} + +output "label8t_context_context" { + value = module.label8t_context.context +} + +output "label8t_context_tags" { + value = module.label8t_context.tags +} + +output "label8t_id" { + value = module.label8t.id +} + +output "label8t_context" { + value = module.label8t.context +} + +output "label8t_tags" { + value = module.label8t.tags +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label8u.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label8u.tf new file mode 100755 index 0000000..499535b --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/label8u.tf @@ -0,0 +1,50 @@ +module "label8u" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "upper" + label_value_case = "upper" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8u_context" { + source = "../../" + + context = module.label8u.context +} + +output "label8u_context_id" { + value = module.label8u_context.id +} + +output "label8u_context_context" { + value = module.label8u_context.context +} + +// debug +output "label8u_context_normalized_context" { + value = module.label8u_context.normalized_context +} + +output "label8u_context_tags" { + value = module.label8u_context.tags +} + +output "label8u_id" { + value = module.label8u.id +} + +output "label8u_context" { + value = module.label8u.context +} + +output "label8u_tags" { + value = module.label8u.tags +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/versions.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/examples/complete/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/exports/context.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/exports/context.tf new file mode 100755 index 0000000..81f99b4 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/exports/context.tf @@ -0,0 +1,202 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/main.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/main.tf new file mode 100755 index 0000000..0deda2b --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/main.tf @@ -0,0 +1,146 @@ +locals { + + defaults = { + label_order = ["namespace", "environment", "stage", "name", "attributes"] + regex_replace_chars = "/[^-a-zA-Z0-9]/" + delimiter = "-" + replacement = "" + id_length_limit = 0 + id_hash_length = 5 + label_key_case = "title" + label_value_case = "lower" + } + + # So far, we have decided not to allow overriding replacement or id_hash_length + replacement = local.defaults.replacement + id_hash_length = local.defaults.id_hash_length + + # The values provided by variables supersede the values inherited from the context object, + # except for tags and attributes which are merged. + input = { + # It would be nice to use coalesce here, but we cannot, because it + # is an error for all the arguments to coalesce to be empty. + enabled = var.enabled == null ? var.context.enabled : var.enabled + namespace = var.namespace == null ? var.context.namespace : var.namespace + environment = var.environment == null ? var.context.environment : var.environment + stage = var.stage == null ? var.context.stage : var.stage + name = var.name == null ? var.context.name : var.name + delimiter = var.delimiter == null ? var.context.delimiter : var.delimiter + # modules tack on attributes (passed by var) to the end of the list (passed by context) + attributes = compact(distinct(concat(coalesce(var.context.attributes, []), coalesce(var.attributes, [])))) + tags = merge(var.context.tags, var.tags) + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + label_order = var.label_order == null ? var.context.label_order : var.label_order + regex_replace_chars = var.regex_replace_chars == null ? var.context.regex_replace_chars : var.regex_replace_chars + id_length_limit = var.id_length_limit == null ? var.context.id_length_limit : var.id_length_limit + label_key_case = var.label_key_case == null ? lookup(var.context, "label_key_case", null) : var.label_key_case + label_value_case = var.label_value_case == null ? lookup(var.context, "label_value_case", null) : var.label_value_case + } + + + enabled = local.input.enabled + regex_replace_chars = coalesce(local.input.regex_replace_chars, local.defaults.regex_replace_chars) + + # string_label_names are names of inputs that are strings (not list of strings) used as labels + string_label_names = ["name", "namespace", "environment", "stage"] + normalized_labels = { for k in local.string_label_names : k => + local.input[k] == null ? "" : replace(local.input[k], local.regex_replace_chars, local.replacement) + } + normalized_attributes = compact(distinct([for v in local.input.attributes : replace(v, local.regex_replace_chars, local.replacement)])) + + formatted_labels = { for k in local.string_label_names : k => local.label_value_case == "none" ? local.normalized_labels[k] : + local.label_value_case == "title" ? title(lower(local.normalized_labels[k])) : + local.label_value_case == "upper" ? upper(local.normalized_labels[k]) : lower(local.normalized_labels[k]) + } + + attributes = compact(distinct([ + for v in local.normalized_attributes : (local.label_value_case == "none" ? v : + local.label_value_case == "title" ? title(lower(v)) : + local.label_value_case == "upper" ? upper(v) : lower(v)) + ])) + + name = local.formatted_labels["name"] + namespace = local.formatted_labels["namespace"] + environment = local.formatted_labels["environment"] + stage = local.formatted_labels["stage"] + + delimiter = local.input.delimiter == null ? local.defaults.delimiter : local.input.delimiter + label_order = local.input.label_order == null ? local.defaults.label_order : coalescelist(local.input.label_order, local.defaults.label_order) + id_length_limit = local.input.id_length_limit == null ? local.defaults.id_length_limit : local.input.id_length_limit + label_key_case = local.input.label_key_case == null ? local.defaults.label_key_case : local.input.label_key_case + label_value_case = local.input.label_value_case == null ? local.defaults.label_value_case : local.input.label_value_case + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + + tags = merge(local.generated_tags, local.input.tags) + + tags_as_list_of_maps = flatten([ + for key in keys(local.tags) : merge( + { + key = key + value = local.tags[key] + }, var.additional_tag_map) + ]) + + tags_context = { + # For AWS we need `Name` to be disambiguated since it has a special meaning + name = local.id + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = local.id_context.attributes + } + + generated_tags = { + for l in keys(local.tags_context) : + local.label_key_case == "upper" ? upper(l) : ( + local.label_key_case == "lower" ? lower(l) : title(lower(l)) + ) => local.tags_context[l] if length(local.tags_context[l]) > 0 + } + + id_context = { + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = join(local.delimiter, local.attributes) + } + + labels = [for l in local.label_order : local.id_context[l] if length(local.id_context[l]) > 0] + + id_full = join(local.delimiter, local.labels) + # Create a truncated ID if needed + delimiter_length = length(local.delimiter) + # Calculate length of normal part of ID, leaving room for delimiter and hash + id_truncated_length_limit = local.id_length_limit - (local.id_hash_length + local.delimiter_length) + # Truncate the ID and ensure a single (not double) trailing delimiter + id_truncated = local.id_truncated_length_limit <= 0 ? "" : "${trimsuffix(substr(local.id_full, 0, local.id_truncated_length_limit), local.delimiter)}${local.delimiter}" + # Support usages that disallow numeric characters. Would prefer tr 0-9 q-z but Terraform does not support it. + id_hash_plus = "${md5(local.id_full)}qrstuvwxyz" + id_hash_case = local.label_value_case == "title" ? title(local.id_hash_plus) : local.label_value_case == "upper" ? upper(local.id_hash_plus) : local.label_value_case == "lower" ? lower(local.id_hash_plus) : local.id_hash_plus + id_hash = replace(local.id_hash_case, local.regex_replace_chars, local.replacement) + # Create the short ID by adding a hash to the end of the truncated ID + id_short = substr("${local.id_truncated}${local.id_hash}", 0, local.id_length_limit) + id = local.id_length_limit != 0 && length(local.id_full) > local.id_length_limit ? local.id_short : local.id_full + + + # Context of this label to pass to other label modules + output_context = { + enabled = local.enabled + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + delimiter = local.delimiter + attributes = local.attributes + tags = local.tags + additional_tag_map = local.additional_tag_map + label_order = local.label_order + regex_replace_chars = local.regex_replace_chars + id_length_limit = local.id_length_limit + label_key_case = local.label_key_case + label_value_case = local.label_value_case + } + +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/outputs.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/outputs.tf new file mode 100755 index 0000000..87ad1be --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/outputs.tf @@ -0,0 +1,88 @@ +output "id" { + value = local.enabled ? local.id : "" + description = "Disambiguated ID restricted to `id_length_limit` characters in total" +} + +output "id_full" { + value = local.enabled ? local.id_full : "" + description = "Disambiguated ID not restricted in length" +} + +output "enabled" { + value = local.enabled + description = "True if module is enabled, false otherwise" +} + +output "namespace" { + value = local.enabled ? local.namespace : "" + description = "Normalized namespace" +} + +output "environment" { + value = local.enabled ? local.environment : "" + description = "Normalized environment" +} + +output "name" { + value = local.enabled ? local.name : "" + description = "Normalized name" +} + +output "stage" { + value = local.enabled ? local.stage : "" + description = "Normalized stage" +} + +output "delimiter" { + value = local.enabled ? local.delimiter : "" + description = "Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes`" +} + +output "attributes" { + value = local.enabled ? local.attributes : [] + description = "List of attributes" +} + +output "tags" { + value = local.enabled ? local.tags : {} + description = "Normalized Tag map" +} + +output "additional_tag_map" { + value = local.additional_tag_map + description = "The merged additional_tag_map" +} + +output "label_order" { + value = local.label_order + description = "The naming order actually used to create the ID" +} + +output "regex_replace_chars" { + value = local.regex_replace_chars + description = "The regex_replace_chars actually used to create the ID" +} + +output "id_length_limit" { + value = local.id_length_limit + description = "The id_length_limit actually used to create the ID, with `0` meaning unlimited" +} + +output "tags_as_list_of_maps" { + value = local.tags_as_list_of_maps + description = "Additional tags as a list of maps, which can be used in several AWS resources" +} + +output "normalized_context" { + value = local.output_context + description = "Normalized context of this module" +} + +output "context" { + value = local.input + description = <<-EOT + Merged but otherwise unmodified input to this module, to be used as context input to other modules. + Note: this version will have null values as defaults, not the values actually used as defaults. +EOT +} + diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/test/Makefile b/.terraform/modules/datadog_integration2.forwarder_rds.this/test/Makefile new file mode 100755 index 0000000..ea15d62 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/test/Makefile @@ -0,0 +1,43 @@ +TEST_HARNESS ?= https://github.com/cloudposse/test-harness.git +TEST_HARNESS_BRANCH ?= master +TEST_HARNESS_PATH = $(realpath .test-harness) +BATS_ARGS ?= --tap +BATS_LOG ?= test.log + +# Define a macro to run the tests +define RUN_TESTS +@echo "Running tests in $(1)" +@cd $(1) && bats $(BATS_ARGS) $(addsuffix .bats,$(addprefix $(TEST_HARNESS_PATH)/test/terraform/,$(TESTS))) +endef + +default: all + +-include Makefile.* + +## Provision the test-harnesss +.test-harness: + [ -d $@ ] || git clone --depth=1 -b $(TEST_HARNESS_BRANCH) $(TEST_HARNESS) $@ + +## Initialize the tests +init: .test-harness + +## Install all dependencies (OS specific) +deps:: + @exit 0 + +## Clean up the test harness +clean: + [ "$(TEST_HARNESS_PATH)" == "/" ] || rm -rf $(TEST_HARNESS_PATH) + +## Run all tests +all: module examples/complete + +## Run basic sanity checks against the module itself +module: export TESTS ?= installed lint get-modules module-pinning get-plugins provider-pinning validate terraform-docs input-descriptions output-descriptions +module: deps + $(call RUN_TESTS, ../) + +## Run tests against example +examples/complete: export TESTS ?= installed lint get-modules get-plugins validate init plan apply +examples/complete: deps + $(call RUN_TESTS, ../$@) diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/test/Makefile.alpine b/.terraform/modules/datadog_integration2.forwarder_rds.this/test/Makefile.alpine new file mode 100755 index 0000000..7925b18 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/test/Makefile.alpine @@ -0,0 +1,5 @@ +ifneq (,$(wildcard /sbin/apk)) +## Install all dependencies for alpine +deps:: init + @apk add --update terraform-docs@cloudposse json2hcl@cloudposse +endif diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/test/src/Makefile b/.terraform/modules/datadog_integration2.forwarder_rds.this/test/src/Makefile new file mode 100755 index 0000000..b772822 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/test/src/Makefile @@ -0,0 +1,30 @@ +export TF_CLI_ARGS_init ?= -get-plugins=true +export TERRAFORM_VERSION ?= $(shell curl -s https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r -M '.current_version' | cut -d. -f1-2) + +.DEFAULT_GOAL : all +.PHONY: all + +## Default target +all: test + +.PHONY : init +## Initialize tests +init: + @exit 0 + +.PHONY : test +## Run tests +test: init + go mod download + go test -v -timeout 60m -run TestExamplesComplete + +## Run tests in docker container +docker/test: + docker run --name terratest --rm -it -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e GITHUB_TOKEN \ + -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" \ + -v $(CURDIR)/../../:/module/ cloudposse/test-harness:latest -C /module/test/src test + +.PHONY : clean +## Clean up files +clean: + rm -rf ../../examples/complete/*.tfstate* diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/test/src/examples_complete_test.go b/.terraform/modules/datadog_integration2.forwarder_rds.this/test/src/examples_complete_test.go new file mode 100755 index 0000000..156e293 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/test/src/examples_complete_test.go @@ -0,0 +1,293 @@ +package test + +import ( + "fmt" + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" + "github.com/qdm12/reprint" + "github.com/stretchr/testify/assert" +) + +type NLContext struct { + AdditionalTagMap map[string]string `json:"additional_tag_map"` + Attributes []string `json:"attributes"` + Delimiter interface{} `json:"delimiter"` + Enabled bool `json:"enabled"` + Environment interface{} `json:"environment"` + LabelOrder []string `json:"label_order"` + Name interface{} `json:"name"` + Namespace interface{} `json:"namespace"` + RegexReplaceChars interface{} `json:"regex_replace_chars"` + Stage interface{} `json:"stage"` + Tags map[string]string `json:"tags"` +} + +// Test the Terraform module in examples/complete using Terratest. +func TestExamplesComplete(t *testing.T) { + t.Parallel() + + terraformOptions := &terraform.Options{ + // The path to where our Terraform code is located + TerraformDir: "../../examples/complete", + Upgrade: true, + } + + // At the end of the test, run `terraform destroy` to clean up any resources that were created + defer terraform.Destroy(t, terraformOptions) + + // This will run `terraform init` and `terraform apply` and fail the test if there are any errors + terraform.InitAndApply(t, terraformOptions) + + expectedLabel1Context := NLContext{ + Enabled: true, + Namespace: "CloudPosse", + Environment: "UAT", + Stage: "build", + Name: "Winston Churchroom", + Attributes: []string{"fire", "water", "earth", "air"}, + Delimiter: "-", + LabelOrder: []string{"name", "environment", "stage", "attributes"}, + Tags: map[string]string{ + "City": "Dublin", + "Environment": "Private", + }, + AdditionalTagMap: map[string]string{}, + } + + var expectedLabel1NormalizedContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel1NormalizedContext) + expectedLabel1NormalizedContext.Namespace = "cloudposse" + expectedLabel1NormalizedContext.Environment = "uat" + expectedLabel1NormalizedContext.Name = "winstonchurchroom" + expectedLabel1NormalizedContext.RegexReplaceChars = "/[^-a-zA-Z0-9]/" + expectedLabel1NormalizedContext.Tags = map[string]string{ + "City": "Dublin", + "Environment": "Private", + "Namespace": "cloudposse", + "Stage": "build", + "Name": "winstonchurchroom-uat-build-fire-water-earth-air", + "Attributes": "fire-water-earth-air", + } + + var label1NormalizedContext, label1Context NLContext + // Run `terraform output` to get the value of an output variable + label1 := terraform.OutputMap(t, terraformOptions, "label1") + label1Tags := terraform.OutputMap(t, terraformOptions, "label1_tags") + terraform.OutputStruct(t, terraformOptions, "label1_normalized_context", &label1NormalizedContext) + terraform.OutputStruct(t, terraformOptions, "label1_context", &label1Context) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1["id"]) + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1Tags["Name"]) + assert.Equal(t, "Dublin", label1Tags["City"]) + assert.Equal(t, "Private", label1Tags["Environment"]) + assert.Equal(t, expectedLabel1NormalizedContext, label1NormalizedContext) + assert.Equal(t, expectedLabel1Context, label1Context) + + label1t1 := terraform.OutputMap(t, terraformOptions, "label1t1") + label1t1Tags := terraform.OutputMap(t, terraformOptions, "label1t1_tags") + assert.Equal(t, "winstonchurchroom-uat-6a0b34", label1t1["id"], + "Extra hash character should be added when trailing delimiter is removed") + assert.Equal(t, label1["id"], label1t1["id_full"], "id_full should not be truncated") + assert.Equal(t, label1t1["id"], label1t1Tags["Name"], "Name tag should match ID") + + label1t2 := terraform.OutputMap(t, terraformOptions, "label1t2") + label1t2Tags := terraform.OutputMap(t, terraformOptions, "label1t2_tags") + assert.Equal(t, "winstonchurchroom-uat-b-6a0b3", label1t2["id"]) + assert.Equal(t, label1t2["id"], label1t2Tags["Name"], "Name tag should match ID") + + // Run `terraform output` to get the value of an output variable + label2 := terraform.OutputMap(t, terraformOptions, "label2") + label2Tags := terraform.OutputMap(t, terraformOptions, "label2_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2["id"]) + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2Tags["Name"]) + assert.Equal(t, "London", label2Tags["City"]) + assert.Equal(t, "Public", label2Tags["Environment"]) + + var expectedLabel3cContext, label3cContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel3cContext) + expectedLabel3cContext.Name = "Starfish" + expectedLabel3cContext.Stage = "release" + expectedLabel3cContext.Delimiter = "." + expectedLabel3cContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3cContext.Tags["Eat"] = "Carrot" + expectedLabel3cContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3c := terraform.OutputMap(t, terraformOptions, "label3c") + label3cTags := terraform.OutputMap(t, terraformOptions, "label3c_tags") + terraform.OutputStruct(t, terraformOptions, "label3c_context", &label3cContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3c["id"]) + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3cTags["Name"]) + assert.Equal(t, expectedLabel3cContext, label3cContext) + + var expectedLabel3nContext, label3nContext NLContext + _ = reprint.FromTo(&expectedLabel1NormalizedContext, &expectedLabel3nContext) + expectedLabel3nContext.Name = "Starfish" + expectedLabel3nContext.Stage = "release" + expectedLabel3nContext.Delimiter = "." + expectedLabel3nContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3nContext.Tags["Eat"] = "Carrot" + expectedLabel3nContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3n := terraform.OutputMap(t, terraformOptions, "label3n") + label3nTags := terraform.OutputMap(t, terraformOptions, "label3n_tags") + terraform.OutputStruct(t, terraformOptions, "label3n_context", &label3nContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3n["id"]) + assert.Equal(t, label1Tags["Name"], label3nTags["Name"], + "Tag from label1 normalized context should overwrite label3n generated tag") + assert.Equal(t, expectedLabel3nContext, label3nContext) + + // Run `terraform output` to get the value of an output variable + label4 := terraform.OutputMap(t, terraformOptions, "label4") + label4Tags := terraform.OutputMap(t, terraformOptions, "label4_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4["id"]) + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4Tags["Name"]) + + // Run `terraform output` to get the value of an output variable + label5 := terraform.OutputMap(t, terraformOptions, "label5") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "", label5["id"]) + + label6f := terraform.OutputMap(t, terraformOptions, "label6f") + label6fTags := terraform.OutputMap(t, terraformOptions, "label6f_tags") + // Test of setting var.label_key_case = "lower", var.label_value_case = "upper" + assert.Equal(t, "CP~UW2~PRD~NULL-LABEL", label6f["id_full"]) + assert.Equal(t, label6f["id_full"], label6f["id"], "id should not be truncated") + assert.Equal(t, label6f["id"], label6fTags["name"], "Name tag should match ID") + + label6t := terraform.OutputMap(t, terraformOptions, "label6t") + label6tTags := terraform.OutputMap(t, terraformOptions, "label6t_tags") + assert.Equal(t, "CPUW2PRDNULL-LABEL", label6t["id_full"]) + assert.NotEqual(t, label6t["id_full"], label6t["id"], "id should be truncated") + assert.Equal(t, label6t["id"], label6tTags["name"], "Name tag should match ID") + assert.Equal(t, label6t["id_length_limit"], fmt.Sprintf("%d", len(label6t["id"])), + "Truncated ID length should equal length limit") + + label7 := terraform.OutputMap(t, terraformOptions, "label7") + assert.Equal(t, "eg-demo-blue-cluster-nodegroup", label7["id"], "var.attributes should be appended after context.attributes") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter=""` returns expected value of id, context id + label8dndID := terraform.Output(t, terraformOptions, "label8dnd_id") + label8dndContextID := terraform.Output(t, terraformOptions, "label8dnd_context_id") + assert.Equal(t, "egdemobluecluster", label8dndID) + assert.Equal(t, label8dndID, label8dndContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter="x"` returns expected value of id, context id + label8dcdID := terraform.Output(t, terraformOptions, "label8dcd_id") + label8dcdContextID := terraform.Output(t, terraformOptions, "label8dcd_context_id") + assert.Equal(t, "egxdemoxbluexcluster", label8dcdID) + assert.Equal(t, label8dcdID, label8dcdContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=lower` returns expected values of id, tags, context tags + label8dExpectedTags := map[string]string{ + "Attributes": "cluster", + "Environment": "demo", + "Name": "eg-demo-blue-cluster", + "Namespace": "eg", + "kubernetes.io/cluster/": "shared", + } + + label8dID := terraform.Output(t, terraformOptions, "label8d_id") + label8dContextID := terraform.Output(t, terraformOptions, "label8d_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8dID) + assert.Equal(t, label8dID, label8dContextID, "ID and context ID should be equal") + + label8dTags := terraform.OutputMap(t, terraformOptions, "label8d_tags") + label8dContextTags := terraform.OutputMap(t, terraformOptions, "label8d_context_tags") + + assert.Exactly(t, label8dExpectedTags, label8dTags, "generated tags are different from expected") + assert.Exactly(t, label8dTags, label8dContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=lower` and `label_value_case=lower` returns expected values of id, tags, context tags + label8lExpectedTags := map[string]string{ + "attributes": "cluster", + "environment": "demo", + "name": "eg-demo-blue-cluster", + "namespace": "eg", + "kubernetes.io/cluster/": "shared", + "upperTEST": "testUPPER", + } + + label8lID := terraform.Output(t, terraformOptions, "label8l_id") + label8lContextID := terraform.Output(t, terraformOptions, "label8l_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8lID) + assert.Equal(t, label8lID, label8lContextID, "ID and context ID should be equal") + + label8lTags := terraform.OutputMap(t, terraformOptions, "label8l_tags") + label8lContextTags := terraform.OutputMap(t, terraformOptions, "label8l_context_tags") + + assert.Exactly(t, label8lExpectedTags, label8lTags, "generated tags are different from expected") + assert.Exactly(t, label8lTags, label8lContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=title` returns expected values of id, tags, context tags + label8tExpectedTags := map[string]string{ + "Attributes": "Eks-Cluster", + "Environment": "Demo", + "Name": "Eg-Demo-Blue-Eks-Cluster", + "Namespace": "Eg", + "kubernetes.io/cluster/": "shared", + } + + label8tID := terraform.Output(t, terraformOptions, "label8t_id") + label8tContextID := terraform.Output(t, terraformOptions, "label8t_context_id") + assert.Equal(t, "Eg-Demo-Blue-Eks-Cluster", label8tID) + assert.Equal(t, label8tID, label8tContextID, "ID and context ID should be equal") + + label8tTags := terraform.OutputMap(t, terraformOptions, "label8t_tags") + label8tContextTags := terraform.OutputMap(t, terraformOptions, "label8t_context_tags") + + assert.Exactly(t, label8tExpectedTags, label8tTags, "generated tags are different from expected") + assert.Exactly(t, label8tTags, label8tContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=upper` and `label_value_case=upper` returns expected values of id, tags, context tags + label8uExpectedTags := map[string]string{ + "ATTRIBUTES": "CLUSTER", + "ENVIRONMENT": "DEMO", + "NAME": "EG-DEMO-BLUE-CLUSTER", + "NAMESPACE": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8uID := terraform.Output(t, terraformOptions, "label8u_id") + label8uContextID := terraform.Output(t, terraformOptions, "label8u_context_id") + assert.Equal(t, "EG-DEMO-BLUE-CLUSTER", label8uID) + assert.Equal(t, label8uID, label8uContextID, "ID and context ID should be equal") + + label8uTags := terraform.OutputMap(t, terraformOptions, "label8u_tags") + label8uContextTags := terraform.OutputMap(t, terraformOptions, "label8u_context_tags") + + assert.Exactly(t, label8uExpectedTags, label8uTags, "generated tags are different from expected") + assert.Exactly(t, label8uTags, label8uContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=none` returns expected values of id, tags, context tags + label8nExpectedTags := map[string]string{ + "Attributes": "eks-ClusteR", + "Environment": "demo", + "Name": "EG-demo-blue-eks-ClusteR", + "Namespace": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8nID := terraform.Output(t, terraformOptions, "label8n_id") + label8nContextID := terraform.Output(t, terraformOptions, "label8n_context_id") + assert.Equal(t, "EG-demo-blue-eks-ClusteR", label8nID) + assert.Equal(t, label8nID, label8nContextID, "ID and context ID should be equal") + + label8nTags := terraform.OutputMap(t, terraformOptions, "label8n_tags") + label8nContextTags := terraform.OutputMap(t, terraformOptions, "label8n_context_tags") + + assert.Exactly(t, label8nExpectedTags, label8nTags, "generated tags are different from expected") + assert.Exactly(t, label8nTags, label8nContextTags, "tags and context tags should be equal") +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/test/src/go.mod b/.terraform/modules/datadog_integration2.forwarder_rds.this/test/src/go.mod new file mode 100755 index 0000000..d866541 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/test/src/go.mod @@ -0,0 +1,9 @@ +module github.com/cloudposse/terraform-null-label + +go 1.14 + +require ( + github.com/gruntwork-io/terratest v0.31.1 + github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 + github.com/stretchr/testify v1.6.1 +) diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/test/src/go.sum b/.terraform/modules/datadog_integration2.forwarder_rds.this/test/src/go.sum new file mode 100755 index 0000000..b8d46b1 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/test/src/go.sum @@ -0,0 +1,595 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= +github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.5/go.mod h1:foo3aIXRQ90zFve3r0QiDsrjGDUwWhKl0ZOQy1CT14k= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= +github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200109221225-a4f60165b7a3/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= +github.com/gruntwork-io/terratest v0.31.1 h1:MPGe/5pGgJAIZ/hb+0LM1KyJKSi/QyxSkHoP9/CBhJg= +github.com/gruntwork-io/terratest v0.31.1/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= +github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4= +github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= +github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= +k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= +k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= +k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= +k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= +k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= +k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= +k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= +modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/variables.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/variables.tf new file mode 100755 index 0000000..40fb268 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/variables.tf @@ -0,0 +1,157 @@ +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds.this/versions.tf b/.terraform/modules/datadog_integration2.forwarder_rds.this/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds.this/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/LICENSE b/.terraform/modules/datadog_integration2.forwarder_rds_label/LICENSE new file mode 100755 index 0000000..c844c70 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017-2020 Cloud Posse, LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/Makefile b/.terraform/modules/datadog_integration2.forwarder_rds_label/Makefile new file mode 100755 index 0000000..97d8087 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/Makefile @@ -0,0 +1,10 @@ +SHELL := /bin/bash + +# List of targets the `readme` target should call before generating the readme +export README_DEPS ?= docs/targets.md docs/terraform.md + +-include $(shell curl -sSL -o .build-harness "https://git.io/build-harness"; echo .build-harness) + +## Lint terraform code +lint: + $(SELF) terraform/install terraform/get-modules terraform/get-plugins terraform/lint terraform/validate diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/README.md b/.terraform/modules/datadog_integration2.forwarder_rds_label/README.md new file mode 100755 index 0000000..32950e4 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/README.md @@ -0,0 +1,938 @@ + +# terraform-null-label [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-null-label.svg)](https://github.com/cloudposse/terraform-null-label/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) + + +[![README Header][readme_header_img]][readme_header_link] + +[![Cloud Posse][logo]](https://cpco.io/homepage) + + + +Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + +This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. +However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). +So if you prefer the term `stage` to `environment` +you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. +- If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. +- If you want the attributes in a different order, you can specify that, too, with the `label_order` list. +- You can set a maximum length for the name, and the module will create a unique name that fits within that length. +- You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. +- The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + +It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. +For example, if you have 10 instances, there should be 10 different labels. +However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + +All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + +**NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. +With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + +- Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. +- Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. +- Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. + + +--- + +This project is part of our comprehensive ["SweetOps"](https://cpco.io/sweetops) approach towards DevOps. +[][share_email] +[][share_googleplus] +[][share_facebook] +[][share_reddit] +[][share_linkedin] +[][share_twitter] + + +[![Terraform Open Source Modules](https://docs.cloudposse.com/images/terraform-open-source-modules.svg)][terraform_modules] + + + +It's 100% Open Source and licensed under the [APACHE2](LICENSE). + + + + + + + +We literally have [*hundreds of terraform modules*][terraform_modules] that are Open Source and well-maintained. Check them out! + + + + + + + +## Security & Compliance [](https://bridgecrew.io/) + +Security scanning is graciously provided by Bridgecrew. Bridgecrew is the leading fully hosted, cloud-native solution providing continuous Terraform security and compliance. + +| Benchmark | Description | +|--------|---------------| +| [![Infrastructure Security](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/general)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=INFRASTRUCTURE+SECURITY) | Infrastructure Security Compliance | +| [![CIS KUBERNETES](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_kubernetes)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+KUBERNETES+V1.5) | Center for Internet Security, KUBERNETES Compliance | +| [![CIS AWS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_aws)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AWS+V1.2) | Center for Internet Security, AWS Compliance | +| [![CIS AZURE](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_azure)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AZURE+V1.1) | Center for Internet Security, AZURE Compliance | +| [![PCI-DSS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/pci)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=PCI-DSS+V3.2) | Payment Card Industry Data Security Standards Compliance | +| [![NIST-800-53](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/nist)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=NIST-800-53) | National Institute of Standards and Technology Compliance | +| [![ISO27001](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/iso)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=ISO27001) | Information Security Management System, ISO/IEC 27001 Compliance | +| [![SOC2](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/soc2)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=SOC2)| Service Organization Control 2 Compliance | +| [![CIS GCP](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_gcp)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+GCP+V1.1) | Center for Internet Security, GCP Compliance | +| [![HIPAA](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/hipaa)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=HIPAA) | Health Insurance Portability and Accountability Compliance | + + + +## Usage + + +**IMPORTANT:** We do not pin modules to versions in our examples because of the +difficulty of keeping the versions in the documentation in sync with the latest released versions. +We highly recommend that in your code you pin the version to the exact version you are +using so that your infrastructure remains stable, and update versions in a +systematic way so that they do not catch you by surprise. + +Also, because of a bug in the Terraform registry ([hashicorp/terraform#21417](https://github.com/hashicorp/terraform/issues/21417)), +the registry shows many of our inputs as required when in fact they are optional. +The table below correctly indicates which inputs are required. + + +### Defaults + +Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. +The context object is a single object that contains all the input values for `terraform-null-label`. +However, each input value can also be specified individually by name as a standard Terraform variable, +and the value of those variables, when set to something other than `null`, will override the value +in the context object. In order to allow chaining of these objects, where the context object input to one +module is transformed and passed to the next module, all the variables default to `null` or empty collections. +The actual default values used when nothing is explicitly set are describe in the documentation below. + +For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, +`terraform-null-label` will actually use the default delimiter `-` (hyphen). + +A non-obvious but intentional consequence of this design is that once a module sets a non-default value, +future modules in the chain cannot reset the value back to the original default. Insted, the new setting +becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, +so once a tag is added, it will remain in the tag set and cannot be removed, although its value can +be overwritten. + +### Simple Example + +```hcl +module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} +``` + +This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` +(you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + +Now reference the label when creating an instance: + +```hcl +resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags +} +``` + +Or define a security group: + +```hcl +resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} +``` + + +### Advanced Example + +Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + +```hcl +module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] +} + +module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] +} +``` + +
+ +### Advanced Example 2 + +Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + +```hcl +tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } +] +``` + +Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + +```hcl +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} +``` + +
+ +### Advanced Example 3 + +See [complete example](./examples/complete) for even more examples. + +This example shows how you can pass the `context` output of one label module to the next label_module, +allowing you to create one label that has the base set of values, and then creating every extra label +as a derivative of that. + +
Click to show + +```hcl +module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} +``` + +This creates label outputs like this: + +```hcl +label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" +} +label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } +} +label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } +} +label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" +} +label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" +} +label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } +} +label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" +} +label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, +] +label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" +} +label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } +} +label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } +} +label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" +} + +``` + +
+ + + + + + + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + + + + +## Share the Love + +Like this project? Please give it a ★ on [our GitHub](https://github.com/cloudposse/terraform-null-label)! (it helps us **a lot**) + +Are you using this project or any of our other projects? Consider [leaving a testimonial][testimonial]. =) + + +## Related Projects + +Check out these related projects. + +- [terraform-terraform-label](https://github.com/cloudposse/terraform-terraform-label) - Terraform Module to define a consistent naming convention by (namespace, environment, stage, name, [attributes]) + + + +## Help + +**Got a question?** We got answers. + +File a GitHub [issue](https://github.com/cloudposse/terraform-null-label/issues), send us an [email][email] or join our [Slack Community][slack]. + +[![README Commercial Support][readme_commercial_support_img]][readme_commercial_support_link] + +## DevOps Accelerator for Startups + + +We are a [**DevOps Accelerator**][commercial_support]. We'll help you build your cloud infrastructure from the ground up so you can own it. Then we'll show you how to operate it and stick around for as long as you need us. + +[![Learn More](https://img.shields.io/badge/learn%20more-success.svg?style=for-the-badge)][commercial_support] + +Work directly with our team of DevOps experts via email, slack, and video conferencing. + +We deliver 10x the value for a fraction of the cost of a full-time engineer. Our track record is not even funny. If you want things done right and you need it done FAST, then we're your best bet. + +- **Reference Architecture.** You'll get everything you need from the ground up built using 100% infrastructure as code. +- **Release Engineering.** You'll have end-to-end CI/CD with unlimited staging environments. +- **Site Reliability Engineering.** You'll have total visibility into your apps and microservices. +- **Security Baseline.** You'll have built-in governance with accountability and audit logs for all changes. +- **GitOps.** You'll be able to operate your infrastructure via Pull Requests. +- **Training.** You'll receive hands-on training so your team can operate what we build. +- **Questions.** You'll have a direct line of communication between our teams via a Shared Slack channel. +- **Troubleshooting.** You'll get help to triage when things aren't working. +- **Code Reviews.** You'll receive constructive feedback on Pull Requests. +- **Bug Fixes.** We'll rapidly work with you to fix any bugs in our projects. + +## Slack Community + +Join our [Open Source Community][slack] on Slack. It's **FREE** for everyone! Our "SweetOps" community is where you get to talk with others who share a similar vision for how to rollout and manage infrastructure. This is the best place to talk shop, ask questions, solicit feedback, and work together as a community to build totally *sweet* infrastructure. + +## Discourse Forums + +Participate in our [Discourse Forums][discourse]. Here you'll find answers to commonly asked questions. Most questions will be related to the enormous number of projects we support on our GitHub. Come here to collaborate on answers, find solutions, and get ideas about the products and services we value. It only takes a minute to get started! Just sign in with SSO using your GitHub account. + +## Newsletter + +Sign up for [our newsletter][newsletter] that covers everything on our technology radar. Receive updates on what we're up to on GitHub as well as awesome new projects we discover. + +## Office Hours + +[Join us every Wednesday via Zoom][office_hours] for our weekly "Lunch & Learn" sessions. It's **FREE** for everyone! + +[![zoom](https://img.cloudposse.com/fit-in/200x200/https://cloudposse.com/wp-content/uploads/2019/08/Powered-by-Zoom.png")][office_hours] + +## Contributing + +### Bug Reports & Feature Requests + +Please use the [issue tracker](https://github.com/cloudposse/terraform-null-label/issues) to report any bugs or file feature requests. + +### Developing + +If you are interested in being a contributor and want to get involved in developing this project or [help out](https://cpco.io/help-out) with our other projects, we would love to hear from you! Shoot us an [email][email]. + +In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. + + 1. **Fork** the repo on GitHub + 2. **Clone** the project to your own machine + 3. **Commit** changes to your own branch + 4. **Push** your work back up to your fork + 5. Submit a **Pull Request** so that we can review your changes + +**NOTE:** Be sure to merge the latest changes from "upstream" before making a pull request! + + +## Copyright + +Copyright © 2017-2021 [Cloud Posse, LLC](https://cpco.io/copyright) + + + +## License + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +See [LICENSE](LICENSE) for full details. + +```text +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +``` + + + + + + + + + +## Trademarks + +All other trademarks referenced herein are the property of their respective owners. + +## About + +This project is maintained and funded by [Cloud Posse, LLC][website]. Like it? Please let us know by [leaving a testimonial][testimonial]! + +[![Cloud Posse][logo]][website] + +We're a [DevOps Professional Services][hire] company based in Los Angeles, CA. We ❤️ [Open Source Software][we_love_open_source]. + +We offer [paid support][commercial_support] on all of our projects. + +Check out [our other projects][github], [follow us on twitter][twitter], [apply for a job][jobs], or [hire us][hire] to help with your cloud strategy and implementation. + + + +### Contributors + + +| [![Erik Osterman][osterman_avatar]][osterman_homepage]
[Erik Osterman][osterman_homepage] | [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]
[Andriy Knysh][aknysh_homepage] | [![Igor Rodionov][goruha_avatar]][goruha_homepage]
[Igor Rodionov][goruha_homepage] | [![Sergey Vasilyev][s2504s_avatar]][s2504s_homepage]
[Sergey Vasilyev][s2504s_homepage] | [![Michael Pereira][MichaelPereira_avatar]][MichaelPereira_homepage]
[Michael Pereira][MichaelPereira_homepage] | [![Jamie Nelson][Jamie-BitFlight_avatar]][Jamie-BitFlight_homepage]
[Jamie Nelson][Jamie-BitFlight_homepage] | [![Vladimir][SweetOps_avatar]][SweetOps_homepage]
[Vladimir][SweetOps_homepage] | [![Daren Desjardins][darend_avatar]][darend_homepage]
[Daren Desjardins][darend_homepage] | [![Maarten van der Hoef][maartenvanderhoef_avatar]][maartenvanderhoef_homepage]
[Maarten van der Hoef][maartenvanderhoef_homepage] | [![Adam Tibbing][tibbing_avatar]][tibbing_homepage]
[Adam Tibbing][tibbing_homepage] | +|---|---|---|---|---|---|---|---|---|---| + + + [osterman_homepage]: https://github.com/osterman + [osterman_avatar]: https://img.cloudposse.com/150x150/https://github.com/osterman.png + [aknysh_homepage]: https://github.com/aknysh + [aknysh_avatar]: https://img.cloudposse.com/150x150/https://github.com/aknysh.png + [goruha_homepage]: https://github.com/goruha + [goruha_avatar]: https://img.cloudposse.com/150x150/https://github.com/goruha.png + [s2504s_homepage]: https://github.com/s2504s + [s2504s_avatar]: https://img.cloudposse.com/150x150/https://github.com/s2504s.png + [MichaelPereira_homepage]: https://github.com/MichaelPereira + [MichaelPereira_avatar]: https://img.cloudposse.com/150x150/https://github.com/MichaelPereira.png + [Jamie-BitFlight_homepage]: https://github.com/Jamie-BitFlight + [Jamie-BitFlight_avatar]: https://img.cloudposse.com/150x150/https://github.com/Jamie-BitFlight.png + [SweetOps_homepage]: https://github.com/SweetOps + [SweetOps_avatar]: https://img.cloudposse.com/150x150/https://github.com/SweetOps.png + [darend_homepage]: https://github.com/darend + [darend_avatar]: https://img.cloudposse.com/150x150/https://github.com/darend.png + [maartenvanderhoef_homepage]: https://github.com/maartenvanderhoef + [maartenvanderhoef_avatar]: https://img.cloudposse.com/150x150/https://github.com/maartenvanderhoef.png + [tibbing_homepage]: https://github.com/tibbing + [tibbing_avatar]: https://img.cloudposse.com/150x150/https://github.com/tibbing.png + +[![README Footer][readme_footer_img]][readme_footer_link] +[![Beacon][beacon]][website] + + [logo]: https://cloudposse.com/logo-300x69.svg + [docs]: https://cpco.io/docs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=docs + [website]: https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=website + [github]: https://cpco.io/github?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=github + [jobs]: https://cpco.io/jobs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=jobs + [hire]: https://cpco.io/hire?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=hire + [slack]: https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=slack + [linkedin]: https://cpco.io/linkedin?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=linkedin + [twitter]: https://cpco.io/twitter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=twitter + [testimonial]: https://cpco.io/leave-testimonial?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=testimonial + [office_hours]: https://cloudposse.com/office-hours?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=office_hours + [newsletter]: https://cpco.io/newsletter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=newsletter + [discourse]: https://ask.sweetops.com/?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=discourse + [email]: https://cpco.io/email?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=email + [commercial_support]: https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=commercial_support + [we_love_open_source]: https://cpco.io/we-love-open-source?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=we_love_open_source + [terraform_modules]: https://cpco.io/terraform-modules?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=terraform_modules + [readme_header_img]: https://cloudposse.com/readme/header/img + [readme_header_link]: https://cloudposse.com/readme/header/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_header_link + [readme_footer_img]: https://cloudposse.com/readme/footer/img + [readme_footer_link]: https://cloudposse.com/readme/footer/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_footer_link + [readme_commercial_support_img]: https://cloudposse.com/readme/commercial-support/img + [readme_commercial_support_link]: https://cloudposse.com/readme/commercial-support/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_commercial_support_link + [share_twitter]: https://twitter.com/intent/tweet/?text=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_linkedin]: https://www.linkedin.com/shareArticle?mini=true&title=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_reddit]: https://reddit.com/submit/?url=https://github.com/cloudposse/terraform-null-label + [share_facebook]: https://facebook.com/sharer/sharer.php?u=https://github.com/cloudposse/terraform-null-label + [share_googleplus]: https://plus.google.com/share?url=https://github.com/cloudposse/terraform-null-label + [share_email]: mailto:?subject=terraform-null-label&body=https://github.com/cloudposse/terraform-null-label + [beacon]: https://ga-beacon.cloudposse.com/UA-76589703-4/cloudposse/terraform-null-label?pixel&cs=github&cm=readme&an=terraform-null-label diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/README.yaml b/.terraform/modules/datadog_integration2.forwarder_rds_label/README.yaml new file mode 100755 index 0000000..42bdb84 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/README.yaml @@ -0,0 +1,618 @@ +name: terraform-null-label +tags: +- aws +- terraform +- terraform-modules +- naming-convention +- name +- namespace +- stage +categories: +- terraform-modules/supported +license: APACHE2 +github_repo: cloudposse/terraform-null-label +badges: +- name: Latest Release + image: https://img.shields.io/github/release/cloudposse/terraform-null-label.svg + url: https://github.com/cloudposse/terraform-null-label/releases/latest +- name: Slack Community + image: https://slack.cloudposse.com/badge.svg + url: https://slack.cloudposse.com +related: +- name: terraform-terraform-label + description: Terraform Module to define a consistent naming convention by (namespace, + environment, stage, name, [attributes]) + url: https://github.com/cloudposse/terraform-terraform-label +description: |- + Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + + This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. + However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). + So if you prefer the term `stage` to `environment` + you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. + - If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. + - If you want the attributes in a different order, you can specify that, too, with the `label_order` list. + - You can set a maximum length for the name, and the module will create a unique name that fits within that length. + - You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. + - The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + + It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. + For example, if you have 10 instances, there should be 10 different labels. + However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + + All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + + **NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. + With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + + - Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. + - Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. + - Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. +usage: |- + ### Defaults + + Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. + The context object is a single object that contains all the input values for `terraform-null-label`. + However, each input value can also be specified individually by name as a standard Terraform variable, + and the value of those variables, when set to something other than `null`, will override the value + in the context object. In order to allow chaining of these objects, where the context object input to one + module is transformed and passed to the next module, all the variables default to `null` or empty collections. + The actual default values used when nothing is explicitly set are describe in the documentation below. + + For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, + `terraform-null-label` will actually use the default delimiter `-` (hyphen). + + A non-obvious but intentional consequence of this design is that once a module sets a non-default value, + future modules in the chain cannot reset the value back to the original default. Insted, the new setting + becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, + so once a tag is added, it will remain in the tag set and cannot be removed, although its value can + be overwritten. + + ### Simple Example + + ```hcl + module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + ``` + + This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` + (you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + + Now reference the label when creating an instance: + + ```hcl + resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags + } + ``` + + Or define a security group: + + ```hcl + resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + } + ``` + + + ### Advanced Example + + Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + + ```hcl + module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] + } + + module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] + } + ``` + +
+ + ### Advanced Example 2 + + Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + + ```hcl + tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } + ] + ``` + + Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + + ```hcl + ################################ + # terraform-null-label example # + ################################ + module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } + } + + ####################### + # Launch template # + ####################### + resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } + } + + ###################### + # Autoscaling group # + ###################### + resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps + } + ``` + +
+ + ### Advanced Example 3 + + See [complete example](./examples/complete) for even more examples. + + This example shows how you can pass the `context` output of one label module to the next label_module, + allowing you to create one label that has the base set of values, and then creating every extra label + as a derivative of that. + +
Click to show + + ```hcl + module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } + } + + module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } + } + + module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } + } + ``` + + This creates label outputs like this: + + ```hcl + label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" + } + label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } + } + label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + } + label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" + } + label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } + } + label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" + } + label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, + ] + label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" + } + label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } + } + label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + } + label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + + ``` + +
+ +include: +- docs/targets.md +- docs/terraform.md +contributors: +- name: Erik Osterman + github: osterman +- name: Andriy Knysh + github: aknysh +- name: Igor Rodionov + github: goruha +- name: Sergey Vasilyev + github: s2504s +- name: Michael Pereira + github: MichaelPereira +- name: Jamie Nelson + github: Jamie-BitFlight +- name: Vladimir + github: SweetOps +- name: Daren Desjardins + github: darend +- name: Maarten van der Hoef + github: maartenvanderhoef +- name: Adam Tibbing + github: tibbing diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/docs/targets.md b/.terraform/modules/datadog_integration2.forwarder_rds_label/docs/targets.md new file mode 100755 index 0000000..3dce8b3 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/docs/targets.md @@ -0,0 +1,12 @@ + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/docs/terraform.md b/.terraform/modules/datadog_integration2.forwarder_rds_label/docs/terraform.md new file mode 100755 index 0000000..d4f48f4 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/docs/terraform.md @@ -0,0 +1,54 @@ + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars new file mode 100755 index 0000000..f7c725f --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars @@ -0,0 +1,12 @@ +namespace = "eg" +stage = "prod" +name = "app" + +tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" +} + +additional_tag_map = { + propagate_at_launch = "true" +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/autoscalinggroup/context.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/autoscalinggroup/context.tf new file mode 100755 index 0000000..b97f05f --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/autoscalinggroup/context.tf @@ -0,0 +1,216 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/autoscalinggroup/main.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/autoscalinggroup/main.tf new file mode 100755 index 0000000..f0d3aa6 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/autoscalinggroup/main.tf @@ -0,0 +1,104 @@ +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + + context = module.this.context +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template { + id = aws_launch_template.default.id + version = "$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} + +################################ +# Provider # +################################ +provider "aws" { + region = "eu-west-1" + + # Make it faster by skipping unneeded checks here + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +############################################################## +# Data sources to get VPC, subnets and security group details +############################################################## +data "aws_vpc" "default" { + default = true +} + +data "aws_subnet_ids" "all" { + vpc_id = data.aws_vpc.default.id +} + +data "aws_security_group" "default" { + vpc_id = data.aws_vpc.default.id + name = "default" +} + +data "aws_ami" "amazon_linux" { + most_recent = true + + owners = ["amazon"] + + filter { + name = "name" + + values = [ + "amzn-ami-hvm-*-x86_64-gp2", + ] + } + + filter { + name = "owner-alias" + + values = [ + "amazon", + ] + } +} + diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/autoscalinggroup/outputs.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/autoscalinggroup/outputs.tf new file mode 100755 index 0000000..f8fcce5 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/autoscalinggroup/outputs.tf @@ -0,0 +1,12 @@ +# terraform-null-label example used here: Output list of tags applied in each format +output "tags_as_list_of_maps" { + value = module.label.tags_as_list_of_maps +} + +output "tags" { + value = module.label.tags +} + +output "id" { + value = module.label.id +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/autoscalinggroup/versions.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/autoscalinggroup/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/autoscalinggroup/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/complete.auto.tfvars b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/complete.auto.tfvars new file mode 100755 index 0000000..e7bc519 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/complete.auto.tfvars @@ -0,0 +1,10 @@ +namespace = "cp" +environment = "uw2" +stage = "prd" +name = "null-label" + +delimiter = "" +id_length_limit = 6 + +label_key_case = "lower" +label_value_case = "upper" diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/context.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/context.tf new file mode 100755 index 0000000..973d4dc --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/context.tf @@ -0,0 +1,217 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label1.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label1.tf new file mode 100755 index 0000000..8da353b --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label1.tf @@ -0,0 +1,42 @@ +module "label1" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label1" { + value = { + id = module.label1.id + name = module.label1.name + namespace = module.label1.namespace + stage = module.label1.stage + attributes = module.label1.attributes + delimiter = module.label1.delimiter + } +} + +output "label1_tags" { + value = module.label1.tags +} + +output "label1_context" { + value = module.label1.context +} + +output "label1_normalized_context" { + value = module.label1.normalized_context +} + + + diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label1t1.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label1t1.tf new file mode 100755 index 0000000..2bcb362 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label1t1.tf @@ -0,0 +1,18 @@ +module "label1t1" { + source = "../../" + + id_length_limit = 28 + + context = module.label1.context +} + +output "label1t1" { + value = { + id = module.label1t1.id + id_full = module.label1t1.id_full + } +} + +output "label1t1_tags" { + value = module.label1t1.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label1t2.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label1t2.tf new file mode 100755 index 0000000..5df651e --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label1t2.tf @@ -0,0 +1,18 @@ +module "label1t2" { + source = "../../" + + id_length_limit = 29 + + context = module.label1.context +} + +output "label1t2" { + value = { + id = module.label1t2.id + id_full = module.label1t2.id_full + } +} + +output "label1t2_tags" { + value = module.label1t2.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label2.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label2.tf new file mode 100755 index 0000000..faf7450 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label2.tf @@ -0,0 +1,42 @@ +module "label2" { + source = "../../" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + regex_replace_chars = "/[^a-zA-Z0-9-+]/" + + additional_tag_map = { + propagate_at_launch = "true" + additional_tag = "yes" + } + + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +output "label2" { + value = { + id = module.label2.id + name = module.label2.name + namespace = module.label2.namespace + stage = module.label2.stage + attributes = module.label2.attributes + delimiter = module.label2.delimiter + } +} + +output "label2_tags" { + value = module.label2.tags +} + +output "label2_tags_as_list_of_maps" { + value = module.label2.tags_as_list_of_maps +} + +output "label2_context" { + value = module.label2.context +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label3c.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label3c.tf new file mode 100755 index 0000000..338a636 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label3c.tf @@ -0,0 +1,36 @@ +module "label3c" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3c" { + value = { + id = module.label3c.id + name = module.label3c.name + namespace = module.label3c.namespace + stage = module.label3c.stage + attributes = module.label3c.attributes + delimiter = module.label3c.delimiter + } +} + +output "label3c_tags" { + value = module.label3c.tags +} + +output "label3c_context" { + value = module.label3c.context +} + +output "label3c_normalized_context" { + value = module.label3c.normalized_context +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label3n.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label3n.tf new file mode 100755 index 0000000..ca51282 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label3n.tf @@ -0,0 +1,36 @@ +module "label3n" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.normalized_context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3n" { + value = { + id = module.label3n.id + name = module.label3n.name + namespace = module.label3n.namespace + stage = module.label3n.stage + attributes = module.label3n.attributes + delimiter = module.label3n.delimiter + } +} + +output "label3n_tags" { + value = module.label3n.tags +} + +output "label3n_context" { + value = module.label3n.context +} + +output "label3n_normalized_context" { + value = module.label3n.normalized_context +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label4.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label4.tf new file mode 100755 index 0000000..74e3ca1 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label4.tf @@ -0,0 +1,34 @@ +module "label4" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + name = "Example Cluster" + attributes = ["big", "fat", "honking", "cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label4" { + value = { + id = module.label4.id + name = module.label4.name + namespace = module.label4.namespace + stage = module.label4.stage + attributes = module.label4.attributes + delimiter = module.label4.delimiter + } +} + +output "label4_tags" { + value = module.label4.tags +} + +output "label4_context" { + value = module.label4.context +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label5.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label5.tf new file mode 100755 index 0000000..0f0a76e --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label5.tf @@ -0,0 +1,33 @@ +module "label5" { + source = "../../" + enabled = false + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + } +} + +output "label5" { + value = { + id = module.label5.id + name = module.label5.name + namespace = module.label5.namespace + stage = module.label5.stage + attributes = module.label5.attributes + delimiter = module.label5.delimiter + } +} + +output "label5_tags" { + value = module.label5.tags +} + +output "label5_context" { + value = module.label5.context +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label6f.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label6f.tf new file mode 100755 index 0000000..1ce1bab --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label6f.tf @@ -0,0 +1,20 @@ +module "label6f" { + source = "../../" + + delimiter = "~" + id_length_limit = 0 + + # Use values from tfvars + context = module.this.context +} + +output "label6f" { + value = { + id = module.label6f.id + id_full = module.label6f.id_full + } +} + +output "label6f_tags" { + value = module.label6f.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label6t.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label6t.tf new file mode 100755 index 0000000..b5d9bc1 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label6t.tf @@ -0,0 +1,19 @@ +module "label6t" { + source = "../../" + + # Use values from tfvars, + # specifically: complete.auto.tfvars + context = module.this.context +} + +output "label6t" { + value = { + id = module.label6t.id + id_full = module.label6t.id_full + id_length_limit = module.this.context.id_length_limit + } +} + +output "label6t_tags" { + value = module.label6t.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label7.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label7.tf new file mode 100755 index 0000000..bb365d4 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label7.tf @@ -0,0 +1,44 @@ +module "label7a" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + } +} + +module "label7" { + source = "../../" + + attributes = ["nodegroup"] + + context = module.label7a.context +} + + +output "label7" { + value = { + id = module.label7.id + name = module.label7.name + namespace = module.label7.namespace + stage = module.label7.stage + attributes = module.label7.attributes + delimiter = module.label7.delimiter + } +} + +output "label7_id" { + value = module.label7.id +} + +output "label7_attributes" { + value = module.label7.attributes +} + +output "label7_context" { + value = module.label7.context +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label8d.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label8d.tf new file mode 100755 index 0000000..4252419 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label8d.tf @@ -0,0 +1,44 @@ +module "label8d" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8d_context" { + source = "../../" + + context = module.label8d.context +} + +output "label8d_context_id" { + value = module.label8d_context.id +} + +output "label8d_context_context" { + value = module.label8d_context.context +} + +output "label8d_context_tags" { + value = module.label8d_context.tags +} + +output "label8d_id" { + value = module.label8d.id +} + +output "label8d_context" { + value = module.label8d.context +} + +output "label8d_tags" { + value = module.label8d.tags +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label8dcd.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label8dcd.tf new file mode 100755 index 0000000..ccdae21 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label8dcd.tf @@ -0,0 +1,24 @@ +module "label8dcd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "x" +} + +module "label8dcd_context" { + source = "../../" + + context = module.label8dcd.context +} + +output "label8dcd_context_id" { + value = module.label8dcd_context.id +} + +output "label8dcd_id" { + value = module.label8dcd.id +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label8dnd.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label8dnd.tf new file mode 100755 index 0000000..2edb378 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label8dnd.tf @@ -0,0 +1,24 @@ +module "label8dnd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "" +} + +module "label8dnd_context" { + source = "../../" + + context = module.label8dnd.context +} + +output "label8dnd_context_id" { + value = module.label8dnd_context.id +} + +output "label8dnd_id" { + value = module.label8dnd.id +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label8l.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label8l.tf new file mode 100755 index 0000000..7462f9e --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label8l.tf @@ -0,0 +1,46 @@ +module "label8l" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "lower" + label_value_case = "lower" + + tags = { + "kubernetes.io/cluster/" = "shared" + "upperTEST" = "testUPPER" + } +} + +module "label8l_context" { + source = "../../" + + context = module.label8l.context +} + +output "label8l_context_id" { + value = module.label8l_context.id +} + +output "label8l_context_context" { + value = module.label8l_context.context +} + +output "label8l_context_tags" { + value = module.label8l_context.tags +} + +output "label8l_id" { + value = module.label8l.id +} + +output "label8l_context" { + value = module.label8l.context +} + +output "label8l_tags" { + value = module.label8l.tags +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label8n.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label8n.tf new file mode 100755 index 0000000..fd4ad57 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label8n.tf @@ -0,0 +1,45 @@ +module "label8n" { + source = "../../" + + enabled = true + namespace = "EG" + environment = "demo" + name = "blue" + attributes = ["eks", "ClusteR"] + delimiter = "-" + label_value_case = "none" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8n_context" { + source = "../../" + + context = module.label8n.context +} + +output "label8n_context_id" { + value = module.label8n_context.id +} + +output "label8n_context_context" { + value = module.label8n_context.context +} + +output "label8n_context_tags" { + value = module.label8n_context.tags +} + +output "label8n_id" { + value = module.label8n.id +} + +output "label8n_context" { + value = module.label8n.context +} + +output "label8n_tags" { + value = module.label8n.tags +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label8t.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label8t.tf new file mode 100755 index 0000000..cb54c7a --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label8t.tf @@ -0,0 +1,45 @@ +module "label8t" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["EKS", "cluster"] + delimiter = "-" + label_key_case = "title" + label_value_case = "title" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8t_context" { + source = "../../" + + context = module.label8t.context +} + +output "label8t_context_id" { + value = module.label8t_context.id +} + +output "label8t_context_context" { + value = module.label8t_context.context +} + +output "label8t_context_tags" { + value = module.label8t_context.tags +} + +output "label8t_id" { + value = module.label8t.id +} + +output "label8t_context" { + value = module.label8t.context +} + +output "label8t_tags" { + value = module.label8t.tags +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label8u.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label8u.tf new file mode 100755 index 0000000..499535b --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/label8u.tf @@ -0,0 +1,50 @@ +module "label8u" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "upper" + label_value_case = "upper" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8u_context" { + source = "../../" + + context = module.label8u.context +} + +output "label8u_context_id" { + value = module.label8u_context.id +} + +output "label8u_context_context" { + value = module.label8u_context.context +} + +// debug +output "label8u_context_normalized_context" { + value = module.label8u_context.normalized_context +} + +output "label8u_context_tags" { + value = module.label8u_context.tags +} + +output "label8u_id" { + value = module.label8u.id +} + +output "label8u_context" { + value = module.label8u.context +} + +output "label8u_tags" { + value = module.label8u.tags +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/versions.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/examples/complete/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/exports/context.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/exports/context.tf new file mode 100755 index 0000000..81f99b4 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/exports/context.tf @@ -0,0 +1,202 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/main.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/main.tf new file mode 100755 index 0000000..0deda2b --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/main.tf @@ -0,0 +1,146 @@ +locals { + + defaults = { + label_order = ["namespace", "environment", "stage", "name", "attributes"] + regex_replace_chars = "/[^-a-zA-Z0-9]/" + delimiter = "-" + replacement = "" + id_length_limit = 0 + id_hash_length = 5 + label_key_case = "title" + label_value_case = "lower" + } + + # So far, we have decided not to allow overriding replacement or id_hash_length + replacement = local.defaults.replacement + id_hash_length = local.defaults.id_hash_length + + # The values provided by variables supersede the values inherited from the context object, + # except for tags and attributes which are merged. + input = { + # It would be nice to use coalesce here, but we cannot, because it + # is an error for all the arguments to coalesce to be empty. + enabled = var.enabled == null ? var.context.enabled : var.enabled + namespace = var.namespace == null ? var.context.namespace : var.namespace + environment = var.environment == null ? var.context.environment : var.environment + stage = var.stage == null ? var.context.stage : var.stage + name = var.name == null ? var.context.name : var.name + delimiter = var.delimiter == null ? var.context.delimiter : var.delimiter + # modules tack on attributes (passed by var) to the end of the list (passed by context) + attributes = compact(distinct(concat(coalesce(var.context.attributes, []), coalesce(var.attributes, [])))) + tags = merge(var.context.tags, var.tags) + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + label_order = var.label_order == null ? var.context.label_order : var.label_order + regex_replace_chars = var.regex_replace_chars == null ? var.context.regex_replace_chars : var.regex_replace_chars + id_length_limit = var.id_length_limit == null ? var.context.id_length_limit : var.id_length_limit + label_key_case = var.label_key_case == null ? lookup(var.context, "label_key_case", null) : var.label_key_case + label_value_case = var.label_value_case == null ? lookup(var.context, "label_value_case", null) : var.label_value_case + } + + + enabled = local.input.enabled + regex_replace_chars = coalesce(local.input.regex_replace_chars, local.defaults.regex_replace_chars) + + # string_label_names are names of inputs that are strings (not list of strings) used as labels + string_label_names = ["name", "namespace", "environment", "stage"] + normalized_labels = { for k in local.string_label_names : k => + local.input[k] == null ? "" : replace(local.input[k], local.regex_replace_chars, local.replacement) + } + normalized_attributes = compact(distinct([for v in local.input.attributes : replace(v, local.regex_replace_chars, local.replacement)])) + + formatted_labels = { for k in local.string_label_names : k => local.label_value_case == "none" ? local.normalized_labels[k] : + local.label_value_case == "title" ? title(lower(local.normalized_labels[k])) : + local.label_value_case == "upper" ? upper(local.normalized_labels[k]) : lower(local.normalized_labels[k]) + } + + attributes = compact(distinct([ + for v in local.normalized_attributes : (local.label_value_case == "none" ? v : + local.label_value_case == "title" ? title(lower(v)) : + local.label_value_case == "upper" ? upper(v) : lower(v)) + ])) + + name = local.formatted_labels["name"] + namespace = local.formatted_labels["namespace"] + environment = local.formatted_labels["environment"] + stage = local.formatted_labels["stage"] + + delimiter = local.input.delimiter == null ? local.defaults.delimiter : local.input.delimiter + label_order = local.input.label_order == null ? local.defaults.label_order : coalescelist(local.input.label_order, local.defaults.label_order) + id_length_limit = local.input.id_length_limit == null ? local.defaults.id_length_limit : local.input.id_length_limit + label_key_case = local.input.label_key_case == null ? local.defaults.label_key_case : local.input.label_key_case + label_value_case = local.input.label_value_case == null ? local.defaults.label_value_case : local.input.label_value_case + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + + tags = merge(local.generated_tags, local.input.tags) + + tags_as_list_of_maps = flatten([ + for key in keys(local.tags) : merge( + { + key = key + value = local.tags[key] + }, var.additional_tag_map) + ]) + + tags_context = { + # For AWS we need `Name` to be disambiguated since it has a special meaning + name = local.id + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = local.id_context.attributes + } + + generated_tags = { + for l in keys(local.tags_context) : + local.label_key_case == "upper" ? upper(l) : ( + local.label_key_case == "lower" ? lower(l) : title(lower(l)) + ) => local.tags_context[l] if length(local.tags_context[l]) > 0 + } + + id_context = { + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = join(local.delimiter, local.attributes) + } + + labels = [for l in local.label_order : local.id_context[l] if length(local.id_context[l]) > 0] + + id_full = join(local.delimiter, local.labels) + # Create a truncated ID if needed + delimiter_length = length(local.delimiter) + # Calculate length of normal part of ID, leaving room for delimiter and hash + id_truncated_length_limit = local.id_length_limit - (local.id_hash_length + local.delimiter_length) + # Truncate the ID and ensure a single (not double) trailing delimiter + id_truncated = local.id_truncated_length_limit <= 0 ? "" : "${trimsuffix(substr(local.id_full, 0, local.id_truncated_length_limit), local.delimiter)}${local.delimiter}" + # Support usages that disallow numeric characters. Would prefer tr 0-9 q-z but Terraform does not support it. + id_hash_plus = "${md5(local.id_full)}qrstuvwxyz" + id_hash_case = local.label_value_case == "title" ? title(local.id_hash_plus) : local.label_value_case == "upper" ? upper(local.id_hash_plus) : local.label_value_case == "lower" ? lower(local.id_hash_plus) : local.id_hash_plus + id_hash = replace(local.id_hash_case, local.regex_replace_chars, local.replacement) + # Create the short ID by adding a hash to the end of the truncated ID + id_short = substr("${local.id_truncated}${local.id_hash}", 0, local.id_length_limit) + id = local.id_length_limit != 0 && length(local.id_full) > local.id_length_limit ? local.id_short : local.id_full + + + # Context of this label to pass to other label modules + output_context = { + enabled = local.enabled + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + delimiter = local.delimiter + attributes = local.attributes + tags = local.tags + additional_tag_map = local.additional_tag_map + label_order = local.label_order + regex_replace_chars = local.regex_replace_chars + id_length_limit = local.id_length_limit + label_key_case = local.label_key_case + label_value_case = local.label_value_case + } + +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/outputs.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/outputs.tf new file mode 100755 index 0000000..87ad1be --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/outputs.tf @@ -0,0 +1,88 @@ +output "id" { + value = local.enabled ? local.id : "" + description = "Disambiguated ID restricted to `id_length_limit` characters in total" +} + +output "id_full" { + value = local.enabled ? local.id_full : "" + description = "Disambiguated ID not restricted in length" +} + +output "enabled" { + value = local.enabled + description = "True if module is enabled, false otherwise" +} + +output "namespace" { + value = local.enabled ? local.namespace : "" + description = "Normalized namespace" +} + +output "environment" { + value = local.enabled ? local.environment : "" + description = "Normalized environment" +} + +output "name" { + value = local.enabled ? local.name : "" + description = "Normalized name" +} + +output "stage" { + value = local.enabled ? local.stage : "" + description = "Normalized stage" +} + +output "delimiter" { + value = local.enabled ? local.delimiter : "" + description = "Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes`" +} + +output "attributes" { + value = local.enabled ? local.attributes : [] + description = "List of attributes" +} + +output "tags" { + value = local.enabled ? local.tags : {} + description = "Normalized Tag map" +} + +output "additional_tag_map" { + value = local.additional_tag_map + description = "The merged additional_tag_map" +} + +output "label_order" { + value = local.label_order + description = "The naming order actually used to create the ID" +} + +output "regex_replace_chars" { + value = local.regex_replace_chars + description = "The regex_replace_chars actually used to create the ID" +} + +output "id_length_limit" { + value = local.id_length_limit + description = "The id_length_limit actually used to create the ID, with `0` meaning unlimited" +} + +output "tags_as_list_of_maps" { + value = local.tags_as_list_of_maps + description = "Additional tags as a list of maps, which can be used in several AWS resources" +} + +output "normalized_context" { + value = local.output_context + description = "Normalized context of this module" +} + +output "context" { + value = local.input + description = <<-EOT + Merged but otherwise unmodified input to this module, to be used as context input to other modules. + Note: this version will have null values as defaults, not the values actually used as defaults. +EOT +} + diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/test/Makefile b/.terraform/modules/datadog_integration2.forwarder_rds_label/test/Makefile new file mode 100755 index 0000000..ea15d62 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/test/Makefile @@ -0,0 +1,43 @@ +TEST_HARNESS ?= https://github.com/cloudposse/test-harness.git +TEST_HARNESS_BRANCH ?= master +TEST_HARNESS_PATH = $(realpath .test-harness) +BATS_ARGS ?= --tap +BATS_LOG ?= test.log + +# Define a macro to run the tests +define RUN_TESTS +@echo "Running tests in $(1)" +@cd $(1) && bats $(BATS_ARGS) $(addsuffix .bats,$(addprefix $(TEST_HARNESS_PATH)/test/terraform/,$(TESTS))) +endef + +default: all + +-include Makefile.* + +## Provision the test-harnesss +.test-harness: + [ -d $@ ] || git clone --depth=1 -b $(TEST_HARNESS_BRANCH) $(TEST_HARNESS) $@ + +## Initialize the tests +init: .test-harness + +## Install all dependencies (OS specific) +deps:: + @exit 0 + +## Clean up the test harness +clean: + [ "$(TEST_HARNESS_PATH)" == "/" ] || rm -rf $(TEST_HARNESS_PATH) + +## Run all tests +all: module examples/complete + +## Run basic sanity checks against the module itself +module: export TESTS ?= installed lint get-modules module-pinning get-plugins provider-pinning validate terraform-docs input-descriptions output-descriptions +module: deps + $(call RUN_TESTS, ../) + +## Run tests against example +examples/complete: export TESTS ?= installed lint get-modules get-plugins validate init plan apply +examples/complete: deps + $(call RUN_TESTS, ../$@) diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/test/Makefile.alpine b/.terraform/modules/datadog_integration2.forwarder_rds_label/test/Makefile.alpine new file mode 100755 index 0000000..7925b18 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/test/Makefile.alpine @@ -0,0 +1,5 @@ +ifneq (,$(wildcard /sbin/apk)) +## Install all dependencies for alpine +deps:: init + @apk add --update terraform-docs@cloudposse json2hcl@cloudposse +endif diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/test/src/Makefile b/.terraform/modules/datadog_integration2.forwarder_rds_label/test/src/Makefile new file mode 100755 index 0000000..b772822 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/test/src/Makefile @@ -0,0 +1,30 @@ +export TF_CLI_ARGS_init ?= -get-plugins=true +export TERRAFORM_VERSION ?= $(shell curl -s https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r -M '.current_version' | cut -d. -f1-2) + +.DEFAULT_GOAL : all +.PHONY: all + +## Default target +all: test + +.PHONY : init +## Initialize tests +init: + @exit 0 + +.PHONY : test +## Run tests +test: init + go mod download + go test -v -timeout 60m -run TestExamplesComplete + +## Run tests in docker container +docker/test: + docker run --name terratest --rm -it -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e GITHUB_TOKEN \ + -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" \ + -v $(CURDIR)/../../:/module/ cloudposse/test-harness:latest -C /module/test/src test + +.PHONY : clean +## Clean up files +clean: + rm -rf ../../examples/complete/*.tfstate* diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/test/src/examples_complete_test.go b/.terraform/modules/datadog_integration2.forwarder_rds_label/test/src/examples_complete_test.go new file mode 100755 index 0000000..156e293 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/test/src/examples_complete_test.go @@ -0,0 +1,293 @@ +package test + +import ( + "fmt" + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" + "github.com/qdm12/reprint" + "github.com/stretchr/testify/assert" +) + +type NLContext struct { + AdditionalTagMap map[string]string `json:"additional_tag_map"` + Attributes []string `json:"attributes"` + Delimiter interface{} `json:"delimiter"` + Enabled bool `json:"enabled"` + Environment interface{} `json:"environment"` + LabelOrder []string `json:"label_order"` + Name interface{} `json:"name"` + Namespace interface{} `json:"namespace"` + RegexReplaceChars interface{} `json:"regex_replace_chars"` + Stage interface{} `json:"stage"` + Tags map[string]string `json:"tags"` +} + +// Test the Terraform module in examples/complete using Terratest. +func TestExamplesComplete(t *testing.T) { + t.Parallel() + + terraformOptions := &terraform.Options{ + // The path to where our Terraform code is located + TerraformDir: "../../examples/complete", + Upgrade: true, + } + + // At the end of the test, run `terraform destroy` to clean up any resources that were created + defer terraform.Destroy(t, terraformOptions) + + // This will run `terraform init` and `terraform apply` and fail the test if there are any errors + terraform.InitAndApply(t, terraformOptions) + + expectedLabel1Context := NLContext{ + Enabled: true, + Namespace: "CloudPosse", + Environment: "UAT", + Stage: "build", + Name: "Winston Churchroom", + Attributes: []string{"fire", "water", "earth", "air"}, + Delimiter: "-", + LabelOrder: []string{"name", "environment", "stage", "attributes"}, + Tags: map[string]string{ + "City": "Dublin", + "Environment": "Private", + }, + AdditionalTagMap: map[string]string{}, + } + + var expectedLabel1NormalizedContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel1NormalizedContext) + expectedLabel1NormalizedContext.Namespace = "cloudposse" + expectedLabel1NormalizedContext.Environment = "uat" + expectedLabel1NormalizedContext.Name = "winstonchurchroom" + expectedLabel1NormalizedContext.RegexReplaceChars = "/[^-a-zA-Z0-9]/" + expectedLabel1NormalizedContext.Tags = map[string]string{ + "City": "Dublin", + "Environment": "Private", + "Namespace": "cloudposse", + "Stage": "build", + "Name": "winstonchurchroom-uat-build-fire-water-earth-air", + "Attributes": "fire-water-earth-air", + } + + var label1NormalizedContext, label1Context NLContext + // Run `terraform output` to get the value of an output variable + label1 := terraform.OutputMap(t, terraformOptions, "label1") + label1Tags := terraform.OutputMap(t, terraformOptions, "label1_tags") + terraform.OutputStruct(t, terraformOptions, "label1_normalized_context", &label1NormalizedContext) + terraform.OutputStruct(t, terraformOptions, "label1_context", &label1Context) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1["id"]) + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1Tags["Name"]) + assert.Equal(t, "Dublin", label1Tags["City"]) + assert.Equal(t, "Private", label1Tags["Environment"]) + assert.Equal(t, expectedLabel1NormalizedContext, label1NormalizedContext) + assert.Equal(t, expectedLabel1Context, label1Context) + + label1t1 := terraform.OutputMap(t, terraformOptions, "label1t1") + label1t1Tags := terraform.OutputMap(t, terraformOptions, "label1t1_tags") + assert.Equal(t, "winstonchurchroom-uat-6a0b34", label1t1["id"], + "Extra hash character should be added when trailing delimiter is removed") + assert.Equal(t, label1["id"], label1t1["id_full"], "id_full should not be truncated") + assert.Equal(t, label1t1["id"], label1t1Tags["Name"], "Name tag should match ID") + + label1t2 := terraform.OutputMap(t, terraformOptions, "label1t2") + label1t2Tags := terraform.OutputMap(t, terraformOptions, "label1t2_tags") + assert.Equal(t, "winstonchurchroom-uat-b-6a0b3", label1t2["id"]) + assert.Equal(t, label1t2["id"], label1t2Tags["Name"], "Name tag should match ID") + + // Run `terraform output` to get the value of an output variable + label2 := terraform.OutputMap(t, terraformOptions, "label2") + label2Tags := terraform.OutputMap(t, terraformOptions, "label2_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2["id"]) + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2Tags["Name"]) + assert.Equal(t, "London", label2Tags["City"]) + assert.Equal(t, "Public", label2Tags["Environment"]) + + var expectedLabel3cContext, label3cContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel3cContext) + expectedLabel3cContext.Name = "Starfish" + expectedLabel3cContext.Stage = "release" + expectedLabel3cContext.Delimiter = "." + expectedLabel3cContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3cContext.Tags["Eat"] = "Carrot" + expectedLabel3cContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3c := terraform.OutputMap(t, terraformOptions, "label3c") + label3cTags := terraform.OutputMap(t, terraformOptions, "label3c_tags") + terraform.OutputStruct(t, terraformOptions, "label3c_context", &label3cContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3c["id"]) + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3cTags["Name"]) + assert.Equal(t, expectedLabel3cContext, label3cContext) + + var expectedLabel3nContext, label3nContext NLContext + _ = reprint.FromTo(&expectedLabel1NormalizedContext, &expectedLabel3nContext) + expectedLabel3nContext.Name = "Starfish" + expectedLabel3nContext.Stage = "release" + expectedLabel3nContext.Delimiter = "." + expectedLabel3nContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3nContext.Tags["Eat"] = "Carrot" + expectedLabel3nContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3n := terraform.OutputMap(t, terraformOptions, "label3n") + label3nTags := terraform.OutputMap(t, terraformOptions, "label3n_tags") + terraform.OutputStruct(t, terraformOptions, "label3n_context", &label3nContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3n["id"]) + assert.Equal(t, label1Tags["Name"], label3nTags["Name"], + "Tag from label1 normalized context should overwrite label3n generated tag") + assert.Equal(t, expectedLabel3nContext, label3nContext) + + // Run `terraform output` to get the value of an output variable + label4 := terraform.OutputMap(t, terraformOptions, "label4") + label4Tags := terraform.OutputMap(t, terraformOptions, "label4_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4["id"]) + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4Tags["Name"]) + + // Run `terraform output` to get the value of an output variable + label5 := terraform.OutputMap(t, terraformOptions, "label5") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "", label5["id"]) + + label6f := terraform.OutputMap(t, terraformOptions, "label6f") + label6fTags := terraform.OutputMap(t, terraformOptions, "label6f_tags") + // Test of setting var.label_key_case = "lower", var.label_value_case = "upper" + assert.Equal(t, "CP~UW2~PRD~NULL-LABEL", label6f["id_full"]) + assert.Equal(t, label6f["id_full"], label6f["id"], "id should not be truncated") + assert.Equal(t, label6f["id"], label6fTags["name"], "Name tag should match ID") + + label6t := terraform.OutputMap(t, terraformOptions, "label6t") + label6tTags := terraform.OutputMap(t, terraformOptions, "label6t_tags") + assert.Equal(t, "CPUW2PRDNULL-LABEL", label6t["id_full"]) + assert.NotEqual(t, label6t["id_full"], label6t["id"], "id should be truncated") + assert.Equal(t, label6t["id"], label6tTags["name"], "Name tag should match ID") + assert.Equal(t, label6t["id_length_limit"], fmt.Sprintf("%d", len(label6t["id"])), + "Truncated ID length should equal length limit") + + label7 := terraform.OutputMap(t, terraformOptions, "label7") + assert.Equal(t, "eg-demo-blue-cluster-nodegroup", label7["id"], "var.attributes should be appended after context.attributes") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter=""` returns expected value of id, context id + label8dndID := terraform.Output(t, terraformOptions, "label8dnd_id") + label8dndContextID := terraform.Output(t, terraformOptions, "label8dnd_context_id") + assert.Equal(t, "egdemobluecluster", label8dndID) + assert.Equal(t, label8dndID, label8dndContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter="x"` returns expected value of id, context id + label8dcdID := terraform.Output(t, terraformOptions, "label8dcd_id") + label8dcdContextID := terraform.Output(t, terraformOptions, "label8dcd_context_id") + assert.Equal(t, "egxdemoxbluexcluster", label8dcdID) + assert.Equal(t, label8dcdID, label8dcdContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=lower` returns expected values of id, tags, context tags + label8dExpectedTags := map[string]string{ + "Attributes": "cluster", + "Environment": "demo", + "Name": "eg-demo-blue-cluster", + "Namespace": "eg", + "kubernetes.io/cluster/": "shared", + } + + label8dID := terraform.Output(t, terraformOptions, "label8d_id") + label8dContextID := terraform.Output(t, terraformOptions, "label8d_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8dID) + assert.Equal(t, label8dID, label8dContextID, "ID and context ID should be equal") + + label8dTags := terraform.OutputMap(t, terraformOptions, "label8d_tags") + label8dContextTags := terraform.OutputMap(t, terraformOptions, "label8d_context_tags") + + assert.Exactly(t, label8dExpectedTags, label8dTags, "generated tags are different from expected") + assert.Exactly(t, label8dTags, label8dContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=lower` and `label_value_case=lower` returns expected values of id, tags, context tags + label8lExpectedTags := map[string]string{ + "attributes": "cluster", + "environment": "demo", + "name": "eg-demo-blue-cluster", + "namespace": "eg", + "kubernetes.io/cluster/": "shared", + "upperTEST": "testUPPER", + } + + label8lID := terraform.Output(t, terraformOptions, "label8l_id") + label8lContextID := terraform.Output(t, terraformOptions, "label8l_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8lID) + assert.Equal(t, label8lID, label8lContextID, "ID and context ID should be equal") + + label8lTags := terraform.OutputMap(t, terraformOptions, "label8l_tags") + label8lContextTags := terraform.OutputMap(t, terraformOptions, "label8l_context_tags") + + assert.Exactly(t, label8lExpectedTags, label8lTags, "generated tags are different from expected") + assert.Exactly(t, label8lTags, label8lContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=title` returns expected values of id, tags, context tags + label8tExpectedTags := map[string]string{ + "Attributes": "Eks-Cluster", + "Environment": "Demo", + "Name": "Eg-Demo-Blue-Eks-Cluster", + "Namespace": "Eg", + "kubernetes.io/cluster/": "shared", + } + + label8tID := terraform.Output(t, terraformOptions, "label8t_id") + label8tContextID := terraform.Output(t, terraformOptions, "label8t_context_id") + assert.Equal(t, "Eg-Demo-Blue-Eks-Cluster", label8tID) + assert.Equal(t, label8tID, label8tContextID, "ID and context ID should be equal") + + label8tTags := terraform.OutputMap(t, terraformOptions, "label8t_tags") + label8tContextTags := terraform.OutputMap(t, terraformOptions, "label8t_context_tags") + + assert.Exactly(t, label8tExpectedTags, label8tTags, "generated tags are different from expected") + assert.Exactly(t, label8tTags, label8tContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=upper` and `label_value_case=upper` returns expected values of id, tags, context tags + label8uExpectedTags := map[string]string{ + "ATTRIBUTES": "CLUSTER", + "ENVIRONMENT": "DEMO", + "NAME": "EG-DEMO-BLUE-CLUSTER", + "NAMESPACE": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8uID := terraform.Output(t, terraformOptions, "label8u_id") + label8uContextID := terraform.Output(t, terraformOptions, "label8u_context_id") + assert.Equal(t, "EG-DEMO-BLUE-CLUSTER", label8uID) + assert.Equal(t, label8uID, label8uContextID, "ID and context ID should be equal") + + label8uTags := terraform.OutputMap(t, terraformOptions, "label8u_tags") + label8uContextTags := terraform.OutputMap(t, terraformOptions, "label8u_context_tags") + + assert.Exactly(t, label8uExpectedTags, label8uTags, "generated tags are different from expected") + assert.Exactly(t, label8uTags, label8uContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=none` returns expected values of id, tags, context tags + label8nExpectedTags := map[string]string{ + "Attributes": "eks-ClusteR", + "Environment": "demo", + "Name": "EG-demo-blue-eks-ClusteR", + "Namespace": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8nID := terraform.Output(t, terraformOptions, "label8n_id") + label8nContextID := terraform.Output(t, terraformOptions, "label8n_context_id") + assert.Equal(t, "EG-demo-blue-eks-ClusteR", label8nID) + assert.Equal(t, label8nID, label8nContextID, "ID and context ID should be equal") + + label8nTags := terraform.OutputMap(t, terraformOptions, "label8n_tags") + label8nContextTags := terraform.OutputMap(t, terraformOptions, "label8n_context_tags") + + assert.Exactly(t, label8nExpectedTags, label8nTags, "generated tags are different from expected") + assert.Exactly(t, label8nTags, label8nContextTags, "tags and context tags should be equal") +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/test/src/go.mod b/.terraform/modules/datadog_integration2.forwarder_rds_label/test/src/go.mod new file mode 100755 index 0000000..d866541 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/test/src/go.mod @@ -0,0 +1,9 @@ +module github.com/cloudposse/terraform-null-label + +go 1.14 + +require ( + github.com/gruntwork-io/terratest v0.31.1 + github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 + github.com/stretchr/testify v1.6.1 +) diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/test/src/go.sum b/.terraform/modules/datadog_integration2.forwarder_rds_label/test/src/go.sum new file mode 100755 index 0000000..b8d46b1 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/test/src/go.sum @@ -0,0 +1,595 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= +github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.5/go.mod h1:foo3aIXRQ90zFve3r0QiDsrjGDUwWhKl0ZOQy1CT14k= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= +github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200109221225-a4f60165b7a3/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= +github.com/gruntwork-io/terratest v0.31.1 h1:MPGe/5pGgJAIZ/hb+0LM1KyJKSi/QyxSkHoP9/CBhJg= +github.com/gruntwork-io/terratest v0.31.1/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= +github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4= +github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= +github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= +k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= +k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= +k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= +k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= +k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= +k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= +k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= +modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/variables.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/variables.tf new file mode 100755 index 0000000..40fb268 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/variables.tf @@ -0,0 +1,157 @@ +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} diff --git a/.terraform/modules/datadog_integration2.forwarder_rds_label/versions.tf b/.terraform/modules/datadog_integration2.forwarder_rds_label/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration2.forwarder_rds_label/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration2.lambda_label/LICENSE b/.terraform/modules/datadog_integration2.lambda_label/LICENSE new file mode 100755 index 0000000..c844c70 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017-2020 Cloud Posse, LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/.terraform/modules/datadog_integration2.lambda_label/Makefile b/.terraform/modules/datadog_integration2.lambda_label/Makefile new file mode 100755 index 0000000..97d8087 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/Makefile @@ -0,0 +1,10 @@ +SHELL := /bin/bash + +# List of targets the `readme` target should call before generating the readme +export README_DEPS ?= docs/targets.md docs/terraform.md + +-include $(shell curl -sSL -o .build-harness "https://git.io/build-harness"; echo .build-harness) + +## Lint terraform code +lint: + $(SELF) terraform/install terraform/get-modules terraform/get-plugins terraform/lint terraform/validate diff --git a/.terraform/modules/datadog_integration2.lambda_label/README.md b/.terraform/modules/datadog_integration2.lambda_label/README.md new file mode 100755 index 0000000..32950e4 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/README.md @@ -0,0 +1,938 @@ + +# terraform-null-label [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-null-label.svg)](https://github.com/cloudposse/terraform-null-label/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) + + +[![README Header][readme_header_img]][readme_header_link] + +[![Cloud Posse][logo]](https://cpco.io/homepage) + + + +Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + +This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. +However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). +So if you prefer the term `stage` to `environment` +you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. +- If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. +- If you want the attributes in a different order, you can specify that, too, with the `label_order` list. +- You can set a maximum length for the name, and the module will create a unique name that fits within that length. +- You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. +- The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + +It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. +For example, if you have 10 instances, there should be 10 different labels. +However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + +All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + +**NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. +With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + +- Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. +- Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. +- Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. + + +--- + +This project is part of our comprehensive ["SweetOps"](https://cpco.io/sweetops) approach towards DevOps. +[][share_email] +[][share_googleplus] +[][share_facebook] +[][share_reddit] +[][share_linkedin] +[][share_twitter] + + +[![Terraform Open Source Modules](https://docs.cloudposse.com/images/terraform-open-source-modules.svg)][terraform_modules] + + + +It's 100% Open Source and licensed under the [APACHE2](LICENSE). + + + + + + + +We literally have [*hundreds of terraform modules*][terraform_modules] that are Open Source and well-maintained. Check them out! + + + + + + + +## Security & Compliance [](https://bridgecrew.io/) + +Security scanning is graciously provided by Bridgecrew. Bridgecrew is the leading fully hosted, cloud-native solution providing continuous Terraform security and compliance. + +| Benchmark | Description | +|--------|---------------| +| [![Infrastructure Security](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/general)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=INFRASTRUCTURE+SECURITY) | Infrastructure Security Compliance | +| [![CIS KUBERNETES](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_kubernetes)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+KUBERNETES+V1.5) | Center for Internet Security, KUBERNETES Compliance | +| [![CIS AWS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_aws)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AWS+V1.2) | Center for Internet Security, AWS Compliance | +| [![CIS AZURE](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_azure)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AZURE+V1.1) | Center for Internet Security, AZURE Compliance | +| [![PCI-DSS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/pci)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=PCI-DSS+V3.2) | Payment Card Industry Data Security Standards Compliance | +| [![NIST-800-53](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/nist)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=NIST-800-53) | National Institute of Standards and Technology Compliance | +| [![ISO27001](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/iso)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=ISO27001) | Information Security Management System, ISO/IEC 27001 Compliance | +| [![SOC2](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/soc2)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=SOC2)| Service Organization Control 2 Compliance | +| [![CIS GCP](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_gcp)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+GCP+V1.1) | Center for Internet Security, GCP Compliance | +| [![HIPAA](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/hipaa)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=HIPAA) | Health Insurance Portability and Accountability Compliance | + + + +## Usage + + +**IMPORTANT:** We do not pin modules to versions in our examples because of the +difficulty of keeping the versions in the documentation in sync with the latest released versions. +We highly recommend that in your code you pin the version to the exact version you are +using so that your infrastructure remains stable, and update versions in a +systematic way so that they do not catch you by surprise. + +Also, because of a bug in the Terraform registry ([hashicorp/terraform#21417](https://github.com/hashicorp/terraform/issues/21417)), +the registry shows many of our inputs as required when in fact they are optional. +The table below correctly indicates which inputs are required. + + +### Defaults + +Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. +The context object is a single object that contains all the input values for `terraform-null-label`. +However, each input value can also be specified individually by name as a standard Terraform variable, +and the value of those variables, when set to something other than `null`, will override the value +in the context object. In order to allow chaining of these objects, where the context object input to one +module is transformed and passed to the next module, all the variables default to `null` or empty collections. +The actual default values used when nothing is explicitly set are describe in the documentation below. + +For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, +`terraform-null-label` will actually use the default delimiter `-` (hyphen). + +A non-obvious but intentional consequence of this design is that once a module sets a non-default value, +future modules in the chain cannot reset the value back to the original default. Insted, the new setting +becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, +so once a tag is added, it will remain in the tag set and cannot be removed, although its value can +be overwritten. + +### Simple Example + +```hcl +module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} +``` + +This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` +(you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + +Now reference the label when creating an instance: + +```hcl +resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags +} +``` + +Or define a security group: + +```hcl +resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} +``` + + +### Advanced Example + +Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + +```hcl +module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] +} + +module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] +} +``` + +
+ +### Advanced Example 2 + +Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + +```hcl +tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } +] +``` + +Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + +```hcl +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} +``` + +
+ +### Advanced Example 3 + +See [complete example](./examples/complete) for even more examples. + +This example shows how you can pass the `context` output of one label module to the next label_module, +allowing you to create one label that has the base set of values, and then creating every extra label +as a derivative of that. + +
Click to show + +```hcl +module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} +``` + +This creates label outputs like this: + +```hcl +label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" +} +label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } +} +label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } +} +label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" +} +label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" +} +label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } +} +label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" +} +label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, +] +label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" +} +label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } +} +label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } +} +label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" +} + +``` + +
+ + + + + + + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + + + + +## Share the Love + +Like this project? Please give it a ★ on [our GitHub](https://github.com/cloudposse/terraform-null-label)! (it helps us **a lot**) + +Are you using this project or any of our other projects? Consider [leaving a testimonial][testimonial]. =) + + +## Related Projects + +Check out these related projects. + +- [terraform-terraform-label](https://github.com/cloudposse/terraform-terraform-label) - Terraform Module to define a consistent naming convention by (namespace, environment, stage, name, [attributes]) + + + +## Help + +**Got a question?** We got answers. + +File a GitHub [issue](https://github.com/cloudposse/terraform-null-label/issues), send us an [email][email] or join our [Slack Community][slack]. + +[![README Commercial Support][readme_commercial_support_img]][readme_commercial_support_link] + +## DevOps Accelerator for Startups + + +We are a [**DevOps Accelerator**][commercial_support]. We'll help you build your cloud infrastructure from the ground up so you can own it. Then we'll show you how to operate it and stick around for as long as you need us. + +[![Learn More](https://img.shields.io/badge/learn%20more-success.svg?style=for-the-badge)][commercial_support] + +Work directly with our team of DevOps experts via email, slack, and video conferencing. + +We deliver 10x the value for a fraction of the cost of a full-time engineer. Our track record is not even funny. If you want things done right and you need it done FAST, then we're your best bet. + +- **Reference Architecture.** You'll get everything you need from the ground up built using 100% infrastructure as code. +- **Release Engineering.** You'll have end-to-end CI/CD with unlimited staging environments. +- **Site Reliability Engineering.** You'll have total visibility into your apps and microservices. +- **Security Baseline.** You'll have built-in governance with accountability and audit logs for all changes. +- **GitOps.** You'll be able to operate your infrastructure via Pull Requests. +- **Training.** You'll receive hands-on training so your team can operate what we build. +- **Questions.** You'll have a direct line of communication between our teams via a Shared Slack channel. +- **Troubleshooting.** You'll get help to triage when things aren't working. +- **Code Reviews.** You'll receive constructive feedback on Pull Requests. +- **Bug Fixes.** We'll rapidly work with you to fix any bugs in our projects. + +## Slack Community + +Join our [Open Source Community][slack] on Slack. It's **FREE** for everyone! Our "SweetOps" community is where you get to talk with others who share a similar vision for how to rollout and manage infrastructure. This is the best place to talk shop, ask questions, solicit feedback, and work together as a community to build totally *sweet* infrastructure. + +## Discourse Forums + +Participate in our [Discourse Forums][discourse]. Here you'll find answers to commonly asked questions. Most questions will be related to the enormous number of projects we support on our GitHub. Come here to collaborate on answers, find solutions, and get ideas about the products and services we value. It only takes a minute to get started! Just sign in with SSO using your GitHub account. + +## Newsletter + +Sign up for [our newsletter][newsletter] that covers everything on our technology radar. Receive updates on what we're up to on GitHub as well as awesome new projects we discover. + +## Office Hours + +[Join us every Wednesday via Zoom][office_hours] for our weekly "Lunch & Learn" sessions. It's **FREE** for everyone! + +[![zoom](https://img.cloudposse.com/fit-in/200x200/https://cloudposse.com/wp-content/uploads/2019/08/Powered-by-Zoom.png")][office_hours] + +## Contributing + +### Bug Reports & Feature Requests + +Please use the [issue tracker](https://github.com/cloudposse/terraform-null-label/issues) to report any bugs or file feature requests. + +### Developing + +If you are interested in being a contributor and want to get involved in developing this project or [help out](https://cpco.io/help-out) with our other projects, we would love to hear from you! Shoot us an [email][email]. + +In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. + + 1. **Fork** the repo on GitHub + 2. **Clone** the project to your own machine + 3. **Commit** changes to your own branch + 4. **Push** your work back up to your fork + 5. Submit a **Pull Request** so that we can review your changes + +**NOTE:** Be sure to merge the latest changes from "upstream" before making a pull request! + + +## Copyright + +Copyright © 2017-2021 [Cloud Posse, LLC](https://cpco.io/copyright) + + + +## License + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +See [LICENSE](LICENSE) for full details. + +```text +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +``` + + + + + + + + + +## Trademarks + +All other trademarks referenced herein are the property of their respective owners. + +## About + +This project is maintained and funded by [Cloud Posse, LLC][website]. Like it? Please let us know by [leaving a testimonial][testimonial]! + +[![Cloud Posse][logo]][website] + +We're a [DevOps Professional Services][hire] company based in Los Angeles, CA. We ❤️ [Open Source Software][we_love_open_source]. + +We offer [paid support][commercial_support] on all of our projects. + +Check out [our other projects][github], [follow us on twitter][twitter], [apply for a job][jobs], or [hire us][hire] to help with your cloud strategy and implementation. + + + +### Contributors + + +| [![Erik Osterman][osterman_avatar]][osterman_homepage]
[Erik Osterman][osterman_homepage] | [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]
[Andriy Knysh][aknysh_homepage] | [![Igor Rodionov][goruha_avatar]][goruha_homepage]
[Igor Rodionov][goruha_homepage] | [![Sergey Vasilyev][s2504s_avatar]][s2504s_homepage]
[Sergey Vasilyev][s2504s_homepage] | [![Michael Pereira][MichaelPereira_avatar]][MichaelPereira_homepage]
[Michael Pereira][MichaelPereira_homepage] | [![Jamie Nelson][Jamie-BitFlight_avatar]][Jamie-BitFlight_homepage]
[Jamie Nelson][Jamie-BitFlight_homepage] | [![Vladimir][SweetOps_avatar]][SweetOps_homepage]
[Vladimir][SweetOps_homepage] | [![Daren Desjardins][darend_avatar]][darend_homepage]
[Daren Desjardins][darend_homepage] | [![Maarten van der Hoef][maartenvanderhoef_avatar]][maartenvanderhoef_homepage]
[Maarten van der Hoef][maartenvanderhoef_homepage] | [![Adam Tibbing][tibbing_avatar]][tibbing_homepage]
[Adam Tibbing][tibbing_homepage] | +|---|---|---|---|---|---|---|---|---|---| + + + [osterman_homepage]: https://github.com/osterman + [osterman_avatar]: https://img.cloudposse.com/150x150/https://github.com/osterman.png + [aknysh_homepage]: https://github.com/aknysh + [aknysh_avatar]: https://img.cloudposse.com/150x150/https://github.com/aknysh.png + [goruha_homepage]: https://github.com/goruha + [goruha_avatar]: https://img.cloudposse.com/150x150/https://github.com/goruha.png + [s2504s_homepage]: https://github.com/s2504s + [s2504s_avatar]: https://img.cloudposse.com/150x150/https://github.com/s2504s.png + [MichaelPereira_homepage]: https://github.com/MichaelPereira + [MichaelPereira_avatar]: https://img.cloudposse.com/150x150/https://github.com/MichaelPereira.png + [Jamie-BitFlight_homepage]: https://github.com/Jamie-BitFlight + [Jamie-BitFlight_avatar]: https://img.cloudposse.com/150x150/https://github.com/Jamie-BitFlight.png + [SweetOps_homepage]: https://github.com/SweetOps + [SweetOps_avatar]: https://img.cloudposse.com/150x150/https://github.com/SweetOps.png + [darend_homepage]: https://github.com/darend + [darend_avatar]: https://img.cloudposse.com/150x150/https://github.com/darend.png + [maartenvanderhoef_homepage]: https://github.com/maartenvanderhoef + [maartenvanderhoef_avatar]: https://img.cloudposse.com/150x150/https://github.com/maartenvanderhoef.png + [tibbing_homepage]: https://github.com/tibbing + [tibbing_avatar]: https://img.cloudposse.com/150x150/https://github.com/tibbing.png + +[![README Footer][readme_footer_img]][readme_footer_link] +[![Beacon][beacon]][website] + + [logo]: https://cloudposse.com/logo-300x69.svg + [docs]: https://cpco.io/docs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=docs + [website]: https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=website + [github]: https://cpco.io/github?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=github + [jobs]: https://cpco.io/jobs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=jobs + [hire]: https://cpco.io/hire?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=hire + [slack]: https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=slack + [linkedin]: https://cpco.io/linkedin?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=linkedin + [twitter]: https://cpco.io/twitter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=twitter + [testimonial]: https://cpco.io/leave-testimonial?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=testimonial + [office_hours]: https://cloudposse.com/office-hours?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=office_hours + [newsletter]: https://cpco.io/newsletter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=newsletter + [discourse]: https://ask.sweetops.com/?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=discourse + [email]: https://cpco.io/email?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=email + [commercial_support]: https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=commercial_support + [we_love_open_source]: https://cpco.io/we-love-open-source?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=we_love_open_source + [terraform_modules]: https://cpco.io/terraform-modules?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=terraform_modules + [readme_header_img]: https://cloudposse.com/readme/header/img + [readme_header_link]: https://cloudposse.com/readme/header/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_header_link + [readme_footer_img]: https://cloudposse.com/readme/footer/img + [readme_footer_link]: https://cloudposse.com/readme/footer/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_footer_link + [readme_commercial_support_img]: https://cloudposse.com/readme/commercial-support/img + [readme_commercial_support_link]: https://cloudposse.com/readme/commercial-support/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_commercial_support_link + [share_twitter]: https://twitter.com/intent/tweet/?text=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_linkedin]: https://www.linkedin.com/shareArticle?mini=true&title=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_reddit]: https://reddit.com/submit/?url=https://github.com/cloudposse/terraform-null-label + [share_facebook]: https://facebook.com/sharer/sharer.php?u=https://github.com/cloudposse/terraform-null-label + [share_googleplus]: https://plus.google.com/share?url=https://github.com/cloudposse/terraform-null-label + [share_email]: mailto:?subject=terraform-null-label&body=https://github.com/cloudposse/terraform-null-label + [beacon]: https://ga-beacon.cloudposse.com/UA-76589703-4/cloudposse/terraform-null-label?pixel&cs=github&cm=readme&an=terraform-null-label diff --git a/.terraform/modules/datadog_integration2.lambda_label/README.yaml b/.terraform/modules/datadog_integration2.lambda_label/README.yaml new file mode 100755 index 0000000..42bdb84 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/README.yaml @@ -0,0 +1,618 @@ +name: terraform-null-label +tags: +- aws +- terraform +- terraform-modules +- naming-convention +- name +- namespace +- stage +categories: +- terraform-modules/supported +license: APACHE2 +github_repo: cloudposse/terraform-null-label +badges: +- name: Latest Release + image: https://img.shields.io/github/release/cloudposse/terraform-null-label.svg + url: https://github.com/cloudposse/terraform-null-label/releases/latest +- name: Slack Community + image: https://slack.cloudposse.com/badge.svg + url: https://slack.cloudposse.com +related: +- name: terraform-terraform-label + description: Terraform Module to define a consistent naming convention by (namespace, + environment, stage, name, [attributes]) + url: https://github.com/cloudposse/terraform-terraform-label +description: |- + Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + + This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. + However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). + So if you prefer the term `stage` to `environment` + you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. + - If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. + - If you want the attributes in a different order, you can specify that, too, with the `label_order` list. + - You can set a maximum length for the name, and the module will create a unique name that fits within that length. + - You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. + - The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + + It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. + For example, if you have 10 instances, there should be 10 different labels. + However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + + All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + + **NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. + With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + + - Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. + - Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. + - Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. +usage: |- + ### Defaults + + Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. + The context object is a single object that contains all the input values for `terraform-null-label`. + However, each input value can also be specified individually by name as a standard Terraform variable, + and the value of those variables, when set to something other than `null`, will override the value + in the context object. In order to allow chaining of these objects, where the context object input to one + module is transformed and passed to the next module, all the variables default to `null` or empty collections. + The actual default values used when nothing is explicitly set are describe in the documentation below. + + For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, + `terraform-null-label` will actually use the default delimiter `-` (hyphen). + + A non-obvious but intentional consequence of this design is that once a module sets a non-default value, + future modules in the chain cannot reset the value back to the original default. Insted, the new setting + becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, + so once a tag is added, it will remain in the tag set and cannot be removed, although its value can + be overwritten. + + ### Simple Example + + ```hcl + module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + ``` + + This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` + (you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + + Now reference the label when creating an instance: + + ```hcl + resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags + } + ``` + + Or define a security group: + + ```hcl + resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + } + ``` + + + ### Advanced Example + + Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + + ```hcl + module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] + } + + module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] + } + ``` + +
+ + ### Advanced Example 2 + + Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + + ```hcl + tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } + ] + ``` + + Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + + ```hcl + ################################ + # terraform-null-label example # + ################################ + module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } + } + + ####################### + # Launch template # + ####################### + resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } + } + + ###################### + # Autoscaling group # + ###################### + resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps + } + ``` + +
+ + ### Advanced Example 3 + + See [complete example](./examples/complete) for even more examples. + + This example shows how you can pass the `context` output of one label module to the next label_module, + allowing you to create one label that has the base set of values, and then creating every extra label + as a derivative of that. + +
Click to show + + ```hcl + module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } + } + + module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } + } + + module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } + } + ``` + + This creates label outputs like this: + + ```hcl + label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" + } + label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } + } + label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + } + label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" + } + label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } + } + label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" + } + label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, + ] + label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" + } + label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } + } + label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + } + label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + + ``` + +
+ +include: +- docs/targets.md +- docs/terraform.md +contributors: +- name: Erik Osterman + github: osterman +- name: Andriy Knysh + github: aknysh +- name: Igor Rodionov + github: goruha +- name: Sergey Vasilyev + github: s2504s +- name: Michael Pereira + github: MichaelPereira +- name: Jamie Nelson + github: Jamie-BitFlight +- name: Vladimir + github: SweetOps +- name: Daren Desjardins + github: darend +- name: Maarten van der Hoef + github: maartenvanderhoef +- name: Adam Tibbing + github: tibbing diff --git a/.terraform/modules/datadog_integration2.lambda_label/docs/targets.md b/.terraform/modules/datadog_integration2.lambda_label/docs/targets.md new file mode 100755 index 0000000..3dce8b3 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/docs/targets.md @@ -0,0 +1,12 @@ + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + diff --git a/.terraform/modules/datadog_integration2.lambda_label/docs/terraform.md b/.terraform/modules/datadog_integration2.lambda_label/docs/terraform.md new file mode 100755 index 0000000..d4f48f4 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/docs/terraform.md @@ -0,0 +1,54 @@ + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars b/.terraform/modules/datadog_integration2.lambda_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars new file mode 100755 index 0000000..f7c725f --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/autoscalinggroup/autoscalinggroup.auto.tfvars @@ -0,0 +1,12 @@ +namespace = "eg" +stage = "prod" +name = "app" + +tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" +} + +additional_tag_map = { + propagate_at_launch = "true" +} diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/autoscalinggroup/context.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/autoscalinggroup/context.tf new file mode 100755 index 0000000..b97f05f --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/autoscalinggroup/context.tf @@ -0,0 +1,216 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/autoscalinggroup/main.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/autoscalinggroup/main.tf new file mode 100755 index 0000000..f0d3aa6 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/autoscalinggroup/main.tf @@ -0,0 +1,104 @@ +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + + context = module.this.context +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template { + id = aws_launch_template.default.id + version = "$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} + +################################ +# Provider # +################################ +provider "aws" { + region = "eu-west-1" + + # Make it faster by skipping unneeded checks here + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +############################################################## +# Data sources to get VPC, subnets and security group details +############################################################## +data "aws_vpc" "default" { + default = true +} + +data "aws_subnet_ids" "all" { + vpc_id = data.aws_vpc.default.id +} + +data "aws_security_group" "default" { + vpc_id = data.aws_vpc.default.id + name = "default" +} + +data "aws_ami" "amazon_linux" { + most_recent = true + + owners = ["amazon"] + + filter { + name = "name" + + values = [ + "amzn-ami-hvm-*-x86_64-gp2", + ] + } + + filter { + name = "owner-alias" + + values = [ + "amazon", + ] + } +} + diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/autoscalinggroup/outputs.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/autoscalinggroup/outputs.tf new file mode 100755 index 0000000..f8fcce5 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/autoscalinggroup/outputs.tf @@ -0,0 +1,12 @@ +# terraform-null-label example used here: Output list of tags applied in each format +output "tags_as_list_of_maps" { + value = module.label.tags_as_list_of_maps +} + +output "tags" { + value = module.label.tags +} + +output "id" { + value = module.label.id +} diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/autoscalinggroup/versions.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/autoscalinggroup/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/autoscalinggroup/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/complete/complete.auto.tfvars b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/complete.auto.tfvars new file mode 100755 index 0000000..e7bc519 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/complete.auto.tfvars @@ -0,0 +1,10 @@ +namespace = "cp" +environment = "uw2" +stage = "prd" +name = "null-label" + +delimiter = "" +id_length_limit = 6 + +label_key_case = "lower" +label_value_case = "upper" diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/complete/context.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/context.tf new file mode 100755 index 0000000..973d4dc --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/context.tf @@ -0,0 +1,217 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label1.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label1.tf new file mode 100755 index 0000000..8da353b --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label1.tf @@ -0,0 +1,42 @@ +module "label1" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label1" { + value = { + id = module.label1.id + name = module.label1.name + namespace = module.label1.namespace + stage = module.label1.stage + attributes = module.label1.attributes + delimiter = module.label1.delimiter + } +} + +output "label1_tags" { + value = module.label1.tags +} + +output "label1_context" { + value = module.label1.context +} + +output "label1_normalized_context" { + value = module.label1.normalized_context +} + + + diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label1t1.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label1t1.tf new file mode 100755 index 0000000..2bcb362 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label1t1.tf @@ -0,0 +1,18 @@ +module "label1t1" { + source = "../../" + + id_length_limit = 28 + + context = module.label1.context +} + +output "label1t1" { + value = { + id = module.label1t1.id + id_full = module.label1t1.id_full + } +} + +output "label1t1_tags" { + value = module.label1t1.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label1t2.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label1t2.tf new file mode 100755 index 0000000..5df651e --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label1t2.tf @@ -0,0 +1,18 @@ +module "label1t2" { + source = "../../" + + id_length_limit = 29 + + context = module.label1.context +} + +output "label1t2" { + value = { + id = module.label1t2.id + id_full = module.label1t2.id_full + } +} + +output "label1t2_tags" { + value = module.label1t2.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label2.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label2.tf new file mode 100755 index 0000000..faf7450 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label2.tf @@ -0,0 +1,42 @@ +module "label2" { + source = "../../" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + regex_replace_chars = "/[^a-zA-Z0-9-+]/" + + additional_tag_map = { + propagate_at_launch = "true" + additional_tag = "yes" + } + + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +output "label2" { + value = { + id = module.label2.id + name = module.label2.name + namespace = module.label2.namespace + stage = module.label2.stage + attributes = module.label2.attributes + delimiter = module.label2.delimiter + } +} + +output "label2_tags" { + value = module.label2.tags +} + +output "label2_tags_as_list_of_maps" { + value = module.label2.tags_as_list_of_maps +} + +output "label2_context" { + value = module.label2.context +} diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label3c.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label3c.tf new file mode 100755 index 0000000..338a636 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label3c.tf @@ -0,0 +1,36 @@ +module "label3c" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3c" { + value = { + id = module.label3c.id + name = module.label3c.name + namespace = module.label3c.namespace + stage = module.label3c.stage + attributes = module.label3c.attributes + delimiter = module.label3c.delimiter + } +} + +output "label3c_tags" { + value = module.label3c.tags +} + +output "label3c_context" { + value = module.label3c.context +} + +output "label3c_normalized_context" { + value = module.label3c.normalized_context +} diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label3n.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label3n.tf new file mode 100755 index 0000000..ca51282 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label3n.tf @@ -0,0 +1,36 @@ +module "label3n" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.normalized_context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3n" { + value = { + id = module.label3n.id + name = module.label3n.name + namespace = module.label3n.namespace + stage = module.label3n.stage + attributes = module.label3n.attributes + delimiter = module.label3n.delimiter + } +} + +output "label3n_tags" { + value = module.label3n.tags +} + +output "label3n_context" { + value = module.label3n.context +} + +output "label3n_normalized_context" { + value = module.label3n.normalized_context +} diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label4.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label4.tf new file mode 100755 index 0000000..74e3ca1 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label4.tf @@ -0,0 +1,34 @@ +module "label4" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + name = "Example Cluster" + attributes = ["big", "fat", "honking", "cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label4" { + value = { + id = module.label4.id + name = module.label4.name + namespace = module.label4.namespace + stage = module.label4.stage + attributes = module.label4.attributes + delimiter = module.label4.delimiter + } +} + +output "label4_tags" { + value = module.label4.tags +} + +output "label4_context" { + value = module.label4.context +} diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label5.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label5.tf new file mode 100755 index 0000000..0f0a76e --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label5.tf @@ -0,0 +1,33 @@ +module "label5" { + source = "../../" + enabled = false + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + } +} + +output "label5" { + value = { + id = module.label5.id + name = module.label5.name + namespace = module.label5.namespace + stage = module.label5.stage + attributes = module.label5.attributes + delimiter = module.label5.delimiter + } +} + +output "label5_tags" { + value = module.label5.tags +} + +output "label5_context" { + value = module.label5.context +} diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label6f.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label6f.tf new file mode 100755 index 0000000..1ce1bab --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label6f.tf @@ -0,0 +1,20 @@ +module "label6f" { + source = "../../" + + delimiter = "~" + id_length_limit = 0 + + # Use values from tfvars + context = module.this.context +} + +output "label6f" { + value = { + id = module.label6f.id + id_full = module.label6f.id_full + } +} + +output "label6f_tags" { + value = module.label6f.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label6t.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label6t.tf new file mode 100755 index 0000000..b5d9bc1 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label6t.tf @@ -0,0 +1,19 @@ +module "label6t" { + source = "../../" + + # Use values from tfvars, + # specifically: complete.auto.tfvars + context = module.this.context +} + +output "label6t" { + value = { + id = module.label6t.id + id_full = module.label6t.id_full + id_length_limit = module.this.context.id_length_limit + } +} + +output "label6t_tags" { + value = module.label6t.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label7.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label7.tf new file mode 100755 index 0000000..bb365d4 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label7.tf @@ -0,0 +1,44 @@ +module "label7a" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + } +} + +module "label7" { + source = "../../" + + attributes = ["nodegroup"] + + context = module.label7a.context +} + + +output "label7" { + value = { + id = module.label7.id + name = module.label7.name + namespace = module.label7.namespace + stage = module.label7.stage + attributes = module.label7.attributes + delimiter = module.label7.delimiter + } +} + +output "label7_id" { + value = module.label7.id +} + +output "label7_attributes" { + value = module.label7.attributes +} + +output "label7_context" { + value = module.label7.context +} diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label8d.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label8d.tf new file mode 100755 index 0000000..4252419 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label8d.tf @@ -0,0 +1,44 @@ +module "label8d" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8d_context" { + source = "../../" + + context = module.label8d.context +} + +output "label8d_context_id" { + value = module.label8d_context.id +} + +output "label8d_context_context" { + value = module.label8d_context.context +} + +output "label8d_context_tags" { + value = module.label8d_context.tags +} + +output "label8d_id" { + value = module.label8d.id +} + +output "label8d_context" { + value = module.label8d.context +} + +output "label8d_tags" { + value = module.label8d.tags +} diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label8dcd.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label8dcd.tf new file mode 100755 index 0000000..ccdae21 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label8dcd.tf @@ -0,0 +1,24 @@ +module "label8dcd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "x" +} + +module "label8dcd_context" { + source = "../../" + + context = module.label8dcd.context +} + +output "label8dcd_context_id" { + value = module.label8dcd_context.id +} + +output "label8dcd_id" { + value = module.label8dcd.id +} diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label8dnd.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label8dnd.tf new file mode 100755 index 0000000..2edb378 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label8dnd.tf @@ -0,0 +1,24 @@ +module "label8dnd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "" +} + +module "label8dnd_context" { + source = "../../" + + context = module.label8dnd.context +} + +output "label8dnd_context_id" { + value = module.label8dnd_context.id +} + +output "label8dnd_id" { + value = module.label8dnd.id +} diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label8l.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label8l.tf new file mode 100755 index 0000000..7462f9e --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label8l.tf @@ -0,0 +1,46 @@ +module "label8l" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "lower" + label_value_case = "lower" + + tags = { + "kubernetes.io/cluster/" = "shared" + "upperTEST" = "testUPPER" + } +} + +module "label8l_context" { + source = "../../" + + context = module.label8l.context +} + +output "label8l_context_id" { + value = module.label8l_context.id +} + +output "label8l_context_context" { + value = module.label8l_context.context +} + +output "label8l_context_tags" { + value = module.label8l_context.tags +} + +output "label8l_id" { + value = module.label8l.id +} + +output "label8l_context" { + value = module.label8l.context +} + +output "label8l_tags" { + value = module.label8l.tags +} diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label8n.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label8n.tf new file mode 100755 index 0000000..fd4ad57 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label8n.tf @@ -0,0 +1,45 @@ +module "label8n" { + source = "../../" + + enabled = true + namespace = "EG" + environment = "demo" + name = "blue" + attributes = ["eks", "ClusteR"] + delimiter = "-" + label_value_case = "none" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8n_context" { + source = "../../" + + context = module.label8n.context +} + +output "label8n_context_id" { + value = module.label8n_context.id +} + +output "label8n_context_context" { + value = module.label8n_context.context +} + +output "label8n_context_tags" { + value = module.label8n_context.tags +} + +output "label8n_id" { + value = module.label8n.id +} + +output "label8n_context" { + value = module.label8n.context +} + +output "label8n_tags" { + value = module.label8n.tags +} diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label8t.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label8t.tf new file mode 100755 index 0000000..cb54c7a --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label8t.tf @@ -0,0 +1,45 @@ +module "label8t" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["EKS", "cluster"] + delimiter = "-" + label_key_case = "title" + label_value_case = "title" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8t_context" { + source = "../../" + + context = module.label8t.context +} + +output "label8t_context_id" { + value = module.label8t_context.id +} + +output "label8t_context_context" { + value = module.label8t_context.context +} + +output "label8t_context_tags" { + value = module.label8t_context.tags +} + +output "label8t_id" { + value = module.label8t.id +} + +output "label8t_context" { + value = module.label8t.context +} + +output "label8t_tags" { + value = module.label8t.tags +} diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label8u.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label8u.tf new file mode 100755 index 0000000..499535b --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/label8u.tf @@ -0,0 +1,50 @@ +module "label8u" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "upper" + label_value_case = "upper" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8u_context" { + source = "../../" + + context = module.label8u.context +} + +output "label8u_context_id" { + value = module.label8u_context.id +} + +output "label8u_context_context" { + value = module.label8u_context.context +} + +// debug +output "label8u_context_normalized_context" { + value = module.label8u_context.normalized_context +} + +output "label8u_context_tags" { + value = module.label8u_context.tags +} + +output "label8u_id" { + value = module.label8u.id +} + +output "label8u_context" { + value = module.label8u.context +} + +output "label8u_tags" { + value = module.label8u.tags +} diff --git a/.terraform/modules/datadog_integration2.lambda_label/examples/complete/versions.tf b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/examples/complete/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration2.lambda_label/exports/context.tf b/.terraform/modules/datadog_integration2.lambda_label/exports/context.tf new file mode 100755 index 0000000..81f99b4 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/exports/context.tf @@ -0,0 +1,202 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration2.lambda_label/main.tf b/.terraform/modules/datadog_integration2.lambda_label/main.tf new file mode 100755 index 0000000..0deda2b --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/main.tf @@ -0,0 +1,146 @@ +locals { + + defaults = { + label_order = ["namespace", "environment", "stage", "name", "attributes"] + regex_replace_chars = "/[^-a-zA-Z0-9]/" + delimiter = "-" + replacement = "" + id_length_limit = 0 + id_hash_length = 5 + label_key_case = "title" + label_value_case = "lower" + } + + # So far, we have decided not to allow overriding replacement or id_hash_length + replacement = local.defaults.replacement + id_hash_length = local.defaults.id_hash_length + + # The values provided by variables supersede the values inherited from the context object, + # except for tags and attributes which are merged. + input = { + # It would be nice to use coalesce here, but we cannot, because it + # is an error for all the arguments to coalesce to be empty. + enabled = var.enabled == null ? var.context.enabled : var.enabled + namespace = var.namespace == null ? var.context.namespace : var.namespace + environment = var.environment == null ? var.context.environment : var.environment + stage = var.stage == null ? var.context.stage : var.stage + name = var.name == null ? var.context.name : var.name + delimiter = var.delimiter == null ? var.context.delimiter : var.delimiter + # modules tack on attributes (passed by var) to the end of the list (passed by context) + attributes = compact(distinct(concat(coalesce(var.context.attributes, []), coalesce(var.attributes, [])))) + tags = merge(var.context.tags, var.tags) + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + label_order = var.label_order == null ? var.context.label_order : var.label_order + regex_replace_chars = var.regex_replace_chars == null ? var.context.regex_replace_chars : var.regex_replace_chars + id_length_limit = var.id_length_limit == null ? var.context.id_length_limit : var.id_length_limit + label_key_case = var.label_key_case == null ? lookup(var.context, "label_key_case", null) : var.label_key_case + label_value_case = var.label_value_case == null ? lookup(var.context, "label_value_case", null) : var.label_value_case + } + + + enabled = local.input.enabled + regex_replace_chars = coalesce(local.input.regex_replace_chars, local.defaults.regex_replace_chars) + + # string_label_names are names of inputs that are strings (not list of strings) used as labels + string_label_names = ["name", "namespace", "environment", "stage"] + normalized_labels = { for k in local.string_label_names : k => + local.input[k] == null ? "" : replace(local.input[k], local.regex_replace_chars, local.replacement) + } + normalized_attributes = compact(distinct([for v in local.input.attributes : replace(v, local.regex_replace_chars, local.replacement)])) + + formatted_labels = { for k in local.string_label_names : k => local.label_value_case == "none" ? local.normalized_labels[k] : + local.label_value_case == "title" ? title(lower(local.normalized_labels[k])) : + local.label_value_case == "upper" ? upper(local.normalized_labels[k]) : lower(local.normalized_labels[k]) + } + + attributes = compact(distinct([ + for v in local.normalized_attributes : (local.label_value_case == "none" ? v : + local.label_value_case == "title" ? title(lower(v)) : + local.label_value_case == "upper" ? upper(v) : lower(v)) + ])) + + name = local.formatted_labels["name"] + namespace = local.formatted_labels["namespace"] + environment = local.formatted_labels["environment"] + stage = local.formatted_labels["stage"] + + delimiter = local.input.delimiter == null ? local.defaults.delimiter : local.input.delimiter + label_order = local.input.label_order == null ? local.defaults.label_order : coalescelist(local.input.label_order, local.defaults.label_order) + id_length_limit = local.input.id_length_limit == null ? local.defaults.id_length_limit : local.input.id_length_limit + label_key_case = local.input.label_key_case == null ? local.defaults.label_key_case : local.input.label_key_case + label_value_case = local.input.label_value_case == null ? local.defaults.label_value_case : local.input.label_value_case + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + + tags = merge(local.generated_tags, local.input.tags) + + tags_as_list_of_maps = flatten([ + for key in keys(local.tags) : merge( + { + key = key + value = local.tags[key] + }, var.additional_tag_map) + ]) + + tags_context = { + # For AWS we need `Name` to be disambiguated since it has a special meaning + name = local.id + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = local.id_context.attributes + } + + generated_tags = { + for l in keys(local.tags_context) : + local.label_key_case == "upper" ? upper(l) : ( + local.label_key_case == "lower" ? lower(l) : title(lower(l)) + ) => local.tags_context[l] if length(local.tags_context[l]) > 0 + } + + id_context = { + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = join(local.delimiter, local.attributes) + } + + labels = [for l in local.label_order : local.id_context[l] if length(local.id_context[l]) > 0] + + id_full = join(local.delimiter, local.labels) + # Create a truncated ID if needed + delimiter_length = length(local.delimiter) + # Calculate length of normal part of ID, leaving room for delimiter and hash + id_truncated_length_limit = local.id_length_limit - (local.id_hash_length + local.delimiter_length) + # Truncate the ID and ensure a single (not double) trailing delimiter + id_truncated = local.id_truncated_length_limit <= 0 ? "" : "${trimsuffix(substr(local.id_full, 0, local.id_truncated_length_limit), local.delimiter)}${local.delimiter}" + # Support usages that disallow numeric characters. Would prefer tr 0-9 q-z but Terraform does not support it. + id_hash_plus = "${md5(local.id_full)}qrstuvwxyz" + id_hash_case = local.label_value_case == "title" ? title(local.id_hash_plus) : local.label_value_case == "upper" ? upper(local.id_hash_plus) : local.label_value_case == "lower" ? lower(local.id_hash_plus) : local.id_hash_plus + id_hash = replace(local.id_hash_case, local.regex_replace_chars, local.replacement) + # Create the short ID by adding a hash to the end of the truncated ID + id_short = substr("${local.id_truncated}${local.id_hash}", 0, local.id_length_limit) + id = local.id_length_limit != 0 && length(local.id_full) > local.id_length_limit ? local.id_short : local.id_full + + + # Context of this label to pass to other label modules + output_context = { + enabled = local.enabled + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + delimiter = local.delimiter + attributes = local.attributes + tags = local.tags + additional_tag_map = local.additional_tag_map + label_order = local.label_order + regex_replace_chars = local.regex_replace_chars + id_length_limit = local.id_length_limit + label_key_case = local.label_key_case + label_value_case = local.label_value_case + } + +} diff --git a/.terraform/modules/datadog_integration2.lambda_label/outputs.tf b/.terraform/modules/datadog_integration2.lambda_label/outputs.tf new file mode 100755 index 0000000..87ad1be --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/outputs.tf @@ -0,0 +1,88 @@ +output "id" { + value = local.enabled ? local.id : "" + description = "Disambiguated ID restricted to `id_length_limit` characters in total" +} + +output "id_full" { + value = local.enabled ? local.id_full : "" + description = "Disambiguated ID not restricted in length" +} + +output "enabled" { + value = local.enabled + description = "True if module is enabled, false otherwise" +} + +output "namespace" { + value = local.enabled ? local.namespace : "" + description = "Normalized namespace" +} + +output "environment" { + value = local.enabled ? local.environment : "" + description = "Normalized environment" +} + +output "name" { + value = local.enabled ? local.name : "" + description = "Normalized name" +} + +output "stage" { + value = local.enabled ? local.stage : "" + description = "Normalized stage" +} + +output "delimiter" { + value = local.enabled ? local.delimiter : "" + description = "Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes`" +} + +output "attributes" { + value = local.enabled ? local.attributes : [] + description = "List of attributes" +} + +output "tags" { + value = local.enabled ? local.tags : {} + description = "Normalized Tag map" +} + +output "additional_tag_map" { + value = local.additional_tag_map + description = "The merged additional_tag_map" +} + +output "label_order" { + value = local.label_order + description = "The naming order actually used to create the ID" +} + +output "regex_replace_chars" { + value = local.regex_replace_chars + description = "The regex_replace_chars actually used to create the ID" +} + +output "id_length_limit" { + value = local.id_length_limit + description = "The id_length_limit actually used to create the ID, with `0` meaning unlimited" +} + +output "tags_as_list_of_maps" { + value = local.tags_as_list_of_maps + description = "Additional tags as a list of maps, which can be used in several AWS resources" +} + +output "normalized_context" { + value = local.output_context + description = "Normalized context of this module" +} + +output "context" { + value = local.input + description = <<-EOT + Merged but otherwise unmodified input to this module, to be used as context input to other modules. + Note: this version will have null values as defaults, not the values actually used as defaults. +EOT +} + diff --git a/.terraform/modules/datadog_integration2.lambda_label/test/Makefile b/.terraform/modules/datadog_integration2.lambda_label/test/Makefile new file mode 100755 index 0000000..ea15d62 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/test/Makefile @@ -0,0 +1,43 @@ +TEST_HARNESS ?= https://github.com/cloudposse/test-harness.git +TEST_HARNESS_BRANCH ?= master +TEST_HARNESS_PATH = $(realpath .test-harness) +BATS_ARGS ?= --tap +BATS_LOG ?= test.log + +# Define a macro to run the tests +define RUN_TESTS +@echo "Running tests in $(1)" +@cd $(1) && bats $(BATS_ARGS) $(addsuffix .bats,$(addprefix $(TEST_HARNESS_PATH)/test/terraform/,$(TESTS))) +endef + +default: all + +-include Makefile.* + +## Provision the test-harnesss +.test-harness: + [ -d $@ ] || git clone --depth=1 -b $(TEST_HARNESS_BRANCH) $(TEST_HARNESS) $@ + +## Initialize the tests +init: .test-harness + +## Install all dependencies (OS specific) +deps:: + @exit 0 + +## Clean up the test harness +clean: + [ "$(TEST_HARNESS_PATH)" == "/" ] || rm -rf $(TEST_HARNESS_PATH) + +## Run all tests +all: module examples/complete + +## Run basic sanity checks against the module itself +module: export TESTS ?= installed lint get-modules module-pinning get-plugins provider-pinning validate terraform-docs input-descriptions output-descriptions +module: deps + $(call RUN_TESTS, ../) + +## Run tests against example +examples/complete: export TESTS ?= installed lint get-modules get-plugins validate init plan apply +examples/complete: deps + $(call RUN_TESTS, ../$@) diff --git a/.terraform/modules/datadog_integration2.lambda_label/test/Makefile.alpine b/.terraform/modules/datadog_integration2.lambda_label/test/Makefile.alpine new file mode 100755 index 0000000..7925b18 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/test/Makefile.alpine @@ -0,0 +1,5 @@ +ifneq (,$(wildcard /sbin/apk)) +## Install all dependencies for alpine +deps:: init + @apk add --update terraform-docs@cloudposse json2hcl@cloudposse +endif diff --git a/.terraform/modules/datadog_integration2.lambda_label/test/src/Makefile b/.terraform/modules/datadog_integration2.lambda_label/test/src/Makefile new file mode 100755 index 0000000..b772822 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/test/src/Makefile @@ -0,0 +1,30 @@ +export TF_CLI_ARGS_init ?= -get-plugins=true +export TERRAFORM_VERSION ?= $(shell curl -s https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r -M '.current_version' | cut -d. -f1-2) + +.DEFAULT_GOAL : all +.PHONY: all + +## Default target +all: test + +.PHONY : init +## Initialize tests +init: + @exit 0 + +.PHONY : test +## Run tests +test: init + go mod download + go test -v -timeout 60m -run TestExamplesComplete + +## Run tests in docker container +docker/test: + docker run --name terratest --rm -it -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e GITHUB_TOKEN \ + -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" \ + -v $(CURDIR)/../../:/module/ cloudposse/test-harness:latest -C /module/test/src test + +.PHONY : clean +## Clean up files +clean: + rm -rf ../../examples/complete/*.tfstate* diff --git a/.terraform/modules/datadog_integration2.lambda_label/test/src/examples_complete_test.go b/.terraform/modules/datadog_integration2.lambda_label/test/src/examples_complete_test.go new file mode 100755 index 0000000..156e293 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/test/src/examples_complete_test.go @@ -0,0 +1,293 @@ +package test + +import ( + "fmt" + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" + "github.com/qdm12/reprint" + "github.com/stretchr/testify/assert" +) + +type NLContext struct { + AdditionalTagMap map[string]string `json:"additional_tag_map"` + Attributes []string `json:"attributes"` + Delimiter interface{} `json:"delimiter"` + Enabled bool `json:"enabled"` + Environment interface{} `json:"environment"` + LabelOrder []string `json:"label_order"` + Name interface{} `json:"name"` + Namespace interface{} `json:"namespace"` + RegexReplaceChars interface{} `json:"regex_replace_chars"` + Stage interface{} `json:"stage"` + Tags map[string]string `json:"tags"` +} + +// Test the Terraform module in examples/complete using Terratest. +func TestExamplesComplete(t *testing.T) { + t.Parallel() + + terraformOptions := &terraform.Options{ + // The path to where our Terraform code is located + TerraformDir: "../../examples/complete", + Upgrade: true, + } + + // At the end of the test, run `terraform destroy` to clean up any resources that were created + defer terraform.Destroy(t, terraformOptions) + + // This will run `terraform init` and `terraform apply` and fail the test if there are any errors + terraform.InitAndApply(t, terraformOptions) + + expectedLabel1Context := NLContext{ + Enabled: true, + Namespace: "CloudPosse", + Environment: "UAT", + Stage: "build", + Name: "Winston Churchroom", + Attributes: []string{"fire", "water", "earth", "air"}, + Delimiter: "-", + LabelOrder: []string{"name", "environment", "stage", "attributes"}, + Tags: map[string]string{ + "City": "Dublin", + "Environment": "Private", + }, + AdditionalTagMap: map[string]string{}, + } + + var expectedLabel1NormalizedContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel1NormalizedContext) + expectedLabel1NormalizedContext.Namespace = "cloudposse" + expectedLabel1NormalizedContext.Environment = "uat" + expectedLabel1NormalizedContext.Name = "winstonchurchroom" + expectedLabel1NormalizedContext.RegexReplaceChars = "/[^-a-zA-Z0-9]/" + expectedLabel1NormalizedContext.Tags = map[string]string{ + "City": "Dublin", + "Environment": "Private", + "Namespace": "cloudposse", + "Stage": "build", + "Name": "winstonchurchroom-uat-build-fire-water-earth-air", + "Attributes": "fire-water-earth-air", + } + + var label1NormalizedContext, label1Context NLContext + // Run `terraform output` to get the value of an output variable + label1 := terraform.OutputMap(t, terraformOptions, "label1") + label1Tags := terraform.OutputMap(t, terraformOptions, "label1_tags") + terraform.OutputStruct(t, terraformOptions, "label1_normalized_context", &label1NormalizedContext) + terraform.OutputStruct(t, terraformOptions, "label1_context", &label1Context) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1["id"]) + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1Tags["Name"]) + assert.Equal(t, "Dublin", label1Tags["City"]) + assert.Equal(t, "Private", label1Tags["Environment"]) + assert.Equal(t, expectedLabel1NormalizedContext, label1NormalizedContext) + assert.Equal(t, expectedLabel1Context, label1Context) + + label1t1 := terraform.OutputMap(t, terraformOptions, "label1t1") + label1t1Tags := terraform.OutputMap(t, terraformOptions, "label1t1_tags") + assert.Equal(t, "winstonchurchroom-uat-6a0b34", label1t1["id"], + "Extra hash character should be added when trailing delimiter is removed") + assert.Equal(t, label1["id"], label1t1["id_full"], "id_full should not be truncated") + assert.Equal(t, label1t1["id"], label1t1Tags["Name"], "Name tag should match ID") + + label1t2 := terraform.OutputMap(t, terraformOptions, "label1t2") + label1t2Tags := terraform.OutputMap(t, terraformOptions, "label1t2_tags") + assert.Equal(t, "winstonchurchroom-uat-b-6a0b3", label1t2["id"]) + assert.Equal(t, label1t2["id"], label1t2Tags["Name"], "Name tag should match ID") + + // Run `terraform output` to get the value of an output variable + label2 := terraform.OutputMap(t, terraformOptions, "label2") + label2Tags := terraform.OutputMap(t, terraformOptions, "label2_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2["id"]) + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2Tags["Name"]) + assert.Equal(t, "London", label2Tags["City"]) + assert.Equal(t, "Public", label2Tags["Environment"]) + + var expectedLabel3cContext, label3cContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel3cContext) + expectedLabel3cContext.Name = "Starfish" + expectedLabel3cContext.Stage = "release" + expectedLabel3cContext.Delimiter = "." + expectedLabel3cContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3cContext.Tags["Eat"] = "Carrot" + expectedLabel3cContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3c := terraform.OutputMap(t, terraformOptions, "label3c") + label3cTags := terraform.OutputMap(t, terraformOptions, "label3c_tags") + terraform.OutputStruct(t, terraformOptions, "label3c_context", &label3cContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3c["id"]) + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3cTags["Name"]) + assert.Equal(t, expectedLabel3cContext, label3cContext) + + var expectedLabel3nContext, label3nContext NLContext + _ = reprint.FromTo(&expectedLabel1NormalizedContext, &expectedLabel3nContext) + expectedLabel3nContext.Name = "Starfish" + expectedLabel3nContext.Stage = "release" + expectedLabel3nContext.Delimiter = "." + expectedLabel3nContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3nContext.Tags["Eat"] = "Carrot" + expectedLabel3nContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3n := terraform.OutputMap(t, terraformOptions, "label3n") + label3nTags := terraform.OutputMap(t, terraformOptions, "label3n_tags") + terraform.OutputStruct(t, terraformOptions, "label3n_context", &label3nContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3n["id"]) + assert.Equal(t, label1Tags["Name"], label3nTags["Name"], + "Tag from label1 normalized context should overwrite label3n generated tag") + assert.Equal(t, expectedLabel3nContext, label3nContext) + + // Run `terraform output` to get the value of an output variable + label4 := terraform.OutputMap(t, terraformOptions, "label4") + label4Tags := terraform.OutputMap(t, terraformOptions, "label4_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4["id"]) + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4Tags["Name"]) + + // Run `terraform output` to get the value of an output variable + label5 := terraform.OutputMap(t, terraformOptions, "label5") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "", label5["id"]) + + label6f := terraform.OutputMap(t, terraformOptions, "label6f") + label6fTags := terraform.OutputMap(t, terraformOptions, "label6f_tags") + // Test of setting var.label_key_case = "lower", var.label_value_case = "upper" + assert.Equal(t, "CP~UW2~PRD~NULL-LABEL", label6f["id_full"]) + assert.Equal(t, label6f["id_full"], label6f["id"], "id should not be truncated") + assert.Equal(t, label6f["id"], label6fTags["name"], "Name tag should match ID") + + label6t := terraform.OutputMap(t, terraformOptions, "label6t") + label6tTags := terraform.OutputMap(t, terraformOptions, "label6t_tags") + assert.Equal(t, "CPUW2PRDNULL-LABEL", label6t["id_full"]) + assert.NotEqual(t, label6t["id_full"], label6t["id"], "id should be truncated") + assert.Equal(t, label6t["id"], label6tTags["name"], "Name tag should match ID") + assert.Equal(t, label6t["id_length_limit"], fmt.Sprintf("%d", len(label6t["id"])), + "Truncated ID length should equal length limit") + + label7 := terraform.OutputMap(t, terraformOptions, "label7") + assert.Equal(t, "eg-demo-blue-cluster-nodegroup", label7["id"], "var.attributes should be appended after context.attributes") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter=""` returns expected value of id, context id + label8dndID := terraform.Output(t, terraformOptions, "label8dnd_id") + label8dndContextID := terraform.Output(t, terraformOptions, "label8dnd_context_id") + assert.Equal(t, "egdemobluecluster", label8dndID) + assert.Equal(t, label8dndID, label8dndContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter="x"` returns expected value of id, context id + label8dcdID := terraform.Output(t, terraformOptions, "label8dcd_id") + label8dcdContextID := terraform.Output(t, terraformOptions, "label8dcd_context_id") + assert.Equal(t, "egxdemoxbluexcluster", label8dcdID) + assert.Equal(t, label8dcdID, label8dcdContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=lower` returns expected values of id, tags, context tags + label8dExpectedTags := map[string]string{ + "Attributes": "cluster", + "Environment": "demo", + "Name": "eg-demo-blue-cluster", + "Namespace": "eg", + "kubernetes.io/cluster/": "shared", + } + + label8dID := terraform.Output(t, terraformOptions, "label8d_id") + label8dContextID := terraform.Output(t, terraformOptions, "label8d_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8dID) + assert.Equal(t, label8dID, label8dContextID, "ID and context ID should be equal") + + label8dTags := terraform.OutputMap(t, terraformOptions, "label8d_tags") + label8dContextTags := terraform.OutputMap(t, terraformOptions, "label8d_context_tags") + + assert.Exactly(t, label8dExpectedTags, label8dTags, "generated tags are different from expected") + assert.Exactly(t, label8dTags, label8dContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=lower` and `label_value_case=lower` returns expected values of id, tags, context tags + label8lExpectedTags := map[string]string{ + "attributes": "cluster", + "environment": "demo", + "name": "eg-demo-blue-cluster", + "namespace": "eg", + "kubernetes.io/cluster/": "shared", + "upperTEST": "testUPPER", + } + + label8lID := terraform.Output(t, terraformOptions, "label8l_id") + label8lContextID := terraform.Output(t, terraformOptions, "label8l_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8lID) + assert.Equal(t, label8lID, label8lContextID, "ID and context ID should be equal") + + label8lTags := terraform.OutputMap(t, terraformOptions, "label8l_tags") + label8lContextTags := terraform.OutputMap(t, terraformOptions, "label8l_context_tags") + + assert.Exactly(t, label8lExpectedTags, label8lTags, "generated tags are different from expected") + assert.Exactly(t, label8lTags, label8lContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=title` returns expected values of id, tags, context tags + label8tExpectedTags := map[string]string{ + "Attributes": "Eks-Cluster", + "Environment": "Demo", + "Name": "Eg-Demo-Blue-Eks-Cluster", + "Namespace": "Eg", + "kubernetes.io/cluster/": "shared", + } + + label8tID := terraform.Output(t, terraformOptions, "label8t_id") + label8tContextID := terraform.Output(t, terraformOptions, "label8t_context_id") + assert.Equal(t, "Eg-Demo-Blue-Eks-Cluster", label8tID) + assert.Equal(t, label8tID, label8tContextID, "ID and context ID should be equal") + + label8tTags := terraform.OutputMap(t, terraformOptions, "label8t_tags") + label8tContextTags := terraform.OutputMap(t, terraformOptions, "label8t_context_tags") + + assert.Exactly(t, label8tExpectedTags, label8tTags, "generated tags are different from expected") + assert.Exactly(t, label8tTags, label8tContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=upper` and `label_value_case=upper` returns expected values of id, tags, context tags + label8uExpectedTags := map[string]string{ + "ATTRIBUTES": "CLUSTER", + "ENVIRONMENT": "DEMO", + "NAME": "EG-DEMO-BLUE-CLUSTER", + "NAMESPACE": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8uID := terraform.Output(t, terraformOptions, "label8u_id") + label8uContextID := terraform.Output(t, terraformOptions, "label8u_context_id") + assert.Equal(t, "EG-DEMO-BLUE-CLUSTER", label8uID) + assert.Equal(t, label8uID, label8uContextID, "ID and context ID should be equal") + + label8uTags := terraform.OutputMap(t, terraformOptions, "label8u_tags") + label8uContextTags := terraform.OutputMap(t, terraformOptions, "label8u_context_tags") + + assert.Exactly(t, label8uExpectedTags, label8uTags, "generated tags are different from expected") + assert.Exactly(t, label8uTags, label8uContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=none` returns expected values of id, tags, context tags + label8nExpectedTags := map[string]string{ + "Attributes": "eks-ClusteR", + "Environment": "demo", + "Name": "EG-demo-blue-eks-ClusteR", + "Namespace": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8nID := terraform.Output(t, terraformOptions, "label8n_id") + label8nContextID := terraform.Output(t, terraformOptions, "label8n_context_id") + assert.Equal(t, "EG-demo-blue-eks-ClusteR", label8nID) + assert.Equal(t, label8nID, label8nContextID, "ID and context ID should be equal") + + label8nTags := terraform.OutputMap(t, terraformOptions, "label8n_tags") + label8nContextTags := terraform.OutputMap(t, terraformOptions, "label8n_context_tags") + + assert.Exactly(t, label8nExpectedTags, label8nTags, "generated tags are different from expected") + assert.Exactly(t, label8nTags, label8nContextTags, "tags and context tags should be equal") +} diff --git a/.terraform/modules/datadog_integration2.lambda_label/test/src/go.mod b/.terraform/modules/datadog_integration2.lambda_label/test/src/go.mod new file mode 100755 index 0000000..d866541 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/test/src/go.mod @@ -0,0 +1,9 @@ +module github.com/cloudposse/terraform-null-label + +go 1.14 + +require ( + github.com/gruntwork-io/terratest v0.31.1 + github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 + github.com/stretchr/testify v1.6.1 +) diff --git a/.terraform/modules/datadog_integration2.lambda_label/test/src/go.sum b/.terraform/modules/datadog_integration2.lambda_label/test/src/go.sum new file mode 100755 index 0000000..b8d46b1 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/test/src/go.sum @@ -0,0 +1,595 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= +github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.5/go.mod h1:foo3aIXRQ90zFve3r0QiDsrjGDUwWhKl0ZOQy1CT14k= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= +github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200109221225-a4f60165b7a3/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= +github.com/gruntwork-io/terratest v0.31.1 h1:MPGe/5pGgJAIZ/hb+0LM1KyJKSi/QyxSkHoP9/CBhJg= +github.com/gruntwork-io/terratest v0.31.1/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= +github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4= +github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= +github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= +k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= +k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= +k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= +k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= +k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= +k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= +k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= +modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/.terraform/modules/datadog_integration2.lambda_label/variables.tf b/.terraform/modules/datadog_integration2.lambda_label/variables.tf new file mode 100755 index 0000000..40fb268 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/variables.tf @@ -0,0 +1,157 @@ +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} diff --git a/.terraform/modules/datadog_integration2.lambda_label/versions.tf b/.terraform/modules/datadog_integration2.lambda_label/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration2.lambda_label/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration2.this/LICENSE b/.terraform/modules/datadog_integration2.this/LICENSE new file mode 100755 index 0000000..c844c70 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017-2020 Cloud Posse, LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/.terraform/modules/datadog_integration2.this/Makefile b/.terraform/modules/datadog_integration2.this/Makefile new file mode 100755 index 0000000..97d8087 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/Makefile @@ -0,0 +1,10 @@ +SHELL := /bin/bash + +# List of targets the `readme` target should call before generating the readme +export README_DEPS ?= docs/targets.md docs/terraform.md + +-include $(shell curl -sSL -o .build-harness "https://git.io/build-harness"; echo .build-harness) + +## Lint terraform code +lint: + $(SELF) terraform/install terraform/get-modules terraform/get-plugins terraform/lint terraform/validate diff --git a/.terraform/modules/datadog_integration2.this/README.md b/.terraform/modules/datadog_integration2.this/README.md new file mode 100755 index 0000000..32950e4 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/README.md @@ -0,0 +1,938 @@ + +# terraform-null-label [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-null-label.svg)](https://github.com/cloudposse/terraform-null-label/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) + + +[![README Header][readme_header_img]][readme_header_link] + +[![Cloud Posse][logo]](https://cpco.io/homepage) + + + +Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + +This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. +However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). +So if you prefer the term `stage` to `environment` +you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. +- If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. +- If you want the attributes in a different order, you can specify that, too, with the `label_order` list. +- You can set a maximum length for the name, and the module will create a unique name that fits within that length. +- You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. +- The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + +It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. +For example, if you have 10 instances, there should be 10 different labels. +However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + +All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + +**NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. +With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + +- Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. +- Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. +- Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. + + +--- + +This project is part of our comprehensive ["SweetOps"](https://cpco.io/sweetops) approach towards DevOps. +[][share_email] +[][share_googleplus] +[][share_facebook] +[][share_reddit] +[][share_linkedin] +[][share_twitter] + + +[![Terraform Open Source Modules](https://docs.cloudposse.com/images/terraform-open-source-modules.svg)][terraform_modules] + + + +It's 100% Open Source and licensed under the [APACHE2](LICENSE). + + + + + + + +We literally have [*hundreds of terraform modules*][terraform_modules] that are Open Source and well-maintained. Check them out! + + + + + + + +## Security & Compliance [](https://bridgecrew.io/) + +Security scanning is graciously provided by Bridgecrew. Bridgecrew is the leading fully hosted, cloud-native solution providing continuous Terraform security and compliance. + +| Benchmark | Description | +|--------|---------------| +| [![Infrastructure Security](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/general)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=INFRASTRUCTURE+SECURITY) | Infrastructure Security Compliance | +| [![CIS KUBERNETES](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_kubernetes)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+KUBERNETES+V1.5) | Center for Internet Security, KUBERNETES Compliance | +| [![CIS AWS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_aws)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AWS+V1.2) | Center for Internet Security, AWS Compliance | +| [![CIS AZURE](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_azure)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AZURE+V1.1) | Center for Internet Security, AZURE Compliance | +| [![PCI-DSS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/pci)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=PCI-DSS+V3.2) | Payment Card Industry Data Security Standards Compliance | +| [![NIST-800-53](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/nist)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=NIST-800-53) | National Institute of Standards and Technology Compliance | +| [![ISO27001](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/iso)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=ISO27001) | Information Security Management System, ISO/IEC 27001 Compliance | +| [![SOC2](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/soc2)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=SOC2)| Service Organization Control 2 Compliance | +| [![CIS GCP](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_gcp)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+GCP+V1.1) | Center for Internet Security, GCP Compliance | +| [![HIPAA](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/hipaa)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=HIPAA) | Health Insurance Portability and Accountability Compliance | + + + +## Usage + + +**IMPORTANT:** We do not pin modules to versions in our examples because of the +difficulty of keeping the versions in the documentation in sync with the latest released versions. +We highly recommend that in your code you pin the version to the exact version you are +using so that your infrastructure remains stable, and update versions in a +systematic way so that they do not catch you by surprise. + +Also, because of a bug in the Terraform registry ([hashicorp/terraform#21417](https://github.com/hashicorp/terraform/issues/21417)), +the registry shows many of our inputs as required when in fact they are optional. +The table below correctly indicates which inputs are required. + + +### Defaults + +Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. +The context object is a single object that contains all the input values for `terraform-null-label`. +However, each input value can also be specified individually by name as a standard Terraform variable, +and the value of those variables, when set to something other than `null`, will override the value +in the context object. In order to allow chaining of these objects, where the context object input to one +module is transformed and passed to the next module, all the variables default to `null` or empty collections. +The actual default values used when nothing is explicitly set are describe in the documentation below. + +For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, +`terraform-null-label` will actually use the default delimiter `-` (hyphen). + +A non-obvious but intentional consequence of this design is that once a module sets a non-default value, +future modules in the chain cannot reset the value back to the original default. Insted, the new setting +becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, +so once a tag is added, it will remain in the tag set and cannot be removed, although its value can +be overwritten. + +### Simple Example + +```hcl +module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} +``` + +This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` +(you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + +Now reference the label when creating an instance: + +```hcl +resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags +} +``` + +Or define a security group: + +```hcl +resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} +``` + + +### Advanced Example + +Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + +```hcl +module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] +} + +module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] +} +``` + +
+ +### Advanced Example 2 + +Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + +```hcl +tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } +] +``` + +Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + +```hcl +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} +``` + +
+ +### Advanced Example 3 + +See [complete example](./examples/complete) for even more examples. + +This example shows how you can pass the `context` output of one label module to the next label_module, +allowing you to create one label that has the base set of values, and then creating every extra label +as a derivative of that. + +
Click to show + +```hcl +module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} +``` + +This creates label outputs like this: + +```hcl +label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" +} +label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } +} +label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } +} +label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" +} +label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" +} +label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } +} +label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" +} +label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, +] +label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" +} +label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } +} +label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } +} +label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" +} + +``` + +
+ + + + + + + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + + + + +## Share the Love + +Like this project? Please give it a ★ on [our GitHub](https://github.com/cloudposse/terraform-null-label)! (it helps us **a lot**) + +Are you using this project or any of our other projects? Consider [leaving a testimonial][testimonial]. =) + + +## Related Projects + +Check out these related projects. + +- [terraform-terraform-label](https://github.com/cloudposse/terraform-terraform-label) - Terraform Module to define a consistent naming convention by (namespace, environment, stage, name, [attributes]) + + + +## Help + +**Got a question?** We got answers. + +File a GitHub [issue](https://github.com/cloudposse/terraform-null-label/issues), send us an [email][email] or join our [Slack Community][slack]. + +[![README Commercial Support][readme_commercial_support_img]][readme_commercial_support_link] + +## DevOps Accelerator for Startups + + +We are a [**DevOps Accelerator**][commercial_support]. We'll help you build your cloud infrastructure from the ground up so you can own it. Then we'll show you how to operate it and stick around for as long as you need us. + +[![Learn More](https://img.shields.io/badge/learn%20more-success.svg?style=for-the-badge)][commercial_support] + +Work directly with our team of DevOps experts via email, slack, and video conferencing. + +We deliver 10x the value for a fraction of the cost of a full-time engineer. Our track record is not even funny. If you want things done right and you need it done FAST, then we're your best bet. + +- **Reference Architecture.** You'll get everything you need from the ground up built using 100% infrastructure as code. +- **Release Engineering.** You'll have end-to-end CI/CD with unlimited staging environments. +- **Site Reliability Engineering.** You'll have total visibility into your apps and microservices. +- **Security Baseline.** You'll have built-in governance with accountability and audit logs for all changes. +- **GitOps.** You'll be able to operate your infrastructure via Pull Requests. +- **Training.** You'll receive hands-on training so your team can operate what we build. +- **Questions.** You'll have a direct line of communication between our teams via a Shared Slack channel. +- **Troubleshooting.** You'll get help to triage when things aren't working. +- **Code Reviews.** You'll receive constructive feedback on Pull Requests. +- **Bug Fixes.** We'll rapidly work with you to fix any bugs in our projects. + +## Slack Community + +Join our [Open Source Community][slack] on Slack. It's **FREE** for everyone! Our "SweetOps" community is where you get to talk with others who share a similar vision for how to rollout and manage infrastructure. This is the best place to talk shop, ask questions, solicit feedback, and work together as a community to build totally *sweet* infrastructure. + +## Discourse Forums + +Participate in our [Discourse Forums][discourse]. Here you'll find answers to commonly asked questions. Most questions will be related to the enormous number of projects we support on our GitHub. Come here to collaborate on answers, find solutions, and get ideas about the products and services we value. It only takes a minute to get started! Just sign in with SSO using your GitHub account. + +## Newsletter + +Sign up for [our newsletter][newsletter] that covers everything on our technology radar. Receive updates on what we're up to on GitHub as well as awesome new projects we discover. + +## Office Hours + +[Join us every Wednesday via Zoom][office_hours] for our weekly "Lunch & Learn" sessions. It's **FREE** for everyone! + +[![zoom](https://img.cloudposse.com/fit-in/200x200/https://cloudposse.com/wp-content/uploads/2019/08/Powered-by-Zoom.png")][office_hours] + +## Contributing + +### Bug Reports & Feature Requests + +Please use the [issue tracker](https://github.com/cloudposse/terraform-null-label/issues) to report any bugs or file feature requests. + +### Developing + +If you are interested in being a contributor and want to get involved in developing this project or [help out](https://cpco.io/help-out) with our other projects, we would love to hear from you! Shoot us an [email][email]. + +In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. + + 1. **Fork** the repo on GitHub + 2. **Clone** the project to your own machine + 3. **Commit** changes to your own branch + 4. **Push** your work back up to your fork + 5. Submit a **Pull Request** so that we can review your changes + +**NOTE:** Be sure to merge the latest changes from "upstream" before making a pull request! + + +## Copyright + +Copyright © 2017-2021 [Cloud Posse, LLC](https://cpco.io/copyright) + + + +## License + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +See [LICENSE](LICENSE) for full details. + +```text +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +``` + + + + + + + + + +## Trademarks + +All other trademarks referenced herein are the property of their respective owners. + +## About + +This project is maintained and funded by [Cloud Posse, LLC][website]. Like it? Please let us know by [leaving a testimonial][testimonial]! + +[![Cloud Posse][logo]][website] + +We're a [DevOps Professional Services][hire] company based in Los Angeles, CA. We ❤️ [Open Source Software][we_love_open_source]. + +We offer [paid support][commercial_support] on all of our projects. + +Check out [our other projects][github], [follow us on twitter][twitter], [apply for a job][jobs], or [hire us][hire] to help with your cloud strategy and implementation. + + + +### Contributors + + +| [![Erik Osterman][osterman_avatar]][osterman_homepage]
[Erik Osterman][osterman_homepage] | [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]
[Andriy Knysh][aknysh_homepage] | [![Igor Rodionov][goruha_avatar]][goruha_homepage]
[Igor Rodionov][goruha_homepage] | [![Sergey Vasilyev][s2504s_avatar]][s2504s_homepage]
[Sergey Vasilyev][s2504s_homepage] | [![Michael Pereira][MichaelPereira_avatar]][MichaelPereira_homepage]
[Michael Pereira][MichaelPereira_homepage] | [![Jamie Nelson][Jamie-BitFlight_avatar]][Jamie-BitFlight_homepage]
[Jamie Nelson][Jamie-BitFlight_homepage] | [![Vladimir][SweetOps_avatar]][SweetOps_homepage]
[Vladimir][SweetOps_homepage] | [![Daren Desjardins][darend_avatar]][darend_homepage]
[Daren Desjardins][darend_homepage] | [![Maarten van der Hoef][maartenvanderhoef_avatar]][maartenvanderhoef_homepage]
[Maarten van der Hoef][maartenvanderhoef_homepage] | [![Adam Tibbing][tibbing_avatar]][tibbing_homepage]
[Adam Tibbing][tibbing_homepage] | +|---|---|---|---|---|---|---|---|---|---| + + + [osterman_homepage]: https://github.com/osterman + [osterman_avatar]: https://img.cloudposse.com/150x150/https://github.com/osterman.png + [aknysh_homepage]: https://github.com/aknysh + [aknysh_avatar]: https://img.cloudposse.com/150x150/https://github.com/aknysh.png + [goruha_homepage]: https://github.com/goruha + [goruha_avatar]: https://img.cloudposse.com/150x150/https://github.com/goruha.png + [s2504s_homepage]: https://github.com/s2504s + [s2504s_avatar]: https://img.cloudposse.com/150x150/https://github.com/s2504s.png + [MichaelPereira_homepage]: https://github.com/MichaelPereira + [MichaelPereira_avatar]: https://img.cloudposse.com/150x150/https://github.com/MichaelPereira.png + [Jamie-BitFlight_homepage]: https://github.com/Jamie-BitFlight + [Jamie-BitFlight_avatar]: https://img.cloudposse.com/150x150/https://github.com/Jamie-BitFlight.png + [SweetOps_homepage]: https://github.com/SweetOps + [SweetOps_avatar]: https://img.cloudposse.com/150x150/https://github.com/SweetOps.png + [darend_homepage]: https://github.com/darend + [darend_avatar]: https://img.cloudposse.com/150x150/https://github.com/darend.png + [maartenvanderhoef_homepage]: https://github.com/maartenvanderhoef + [maartenvanderhoef_avatar]: https://img.cloudposse.com/150x150/https://github.com/maartenvanderhoef.png + [tibbing_homepage]: https://github.com/tibbing + [tibbing_avatar]: https://img.cloudposse.com/150x150/https://github.com/tibbing.png + +[![README Footer][readme_footer_img]][readme_footer_link] +[![Beacon][beacon]][website] + + [logo]: https://cloudposse.com/logo-300x69.svg + [docs]: https://cpco.io/docs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=docs + [website]: https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=website + [github]: https://cpco.io/github?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=github + [jobs]: https://cpco.io/jobs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=jobs + [hire]: https://cpco.io/hire?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=hire + [slack]: https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=slack + [linkedin]: https://cpco.io/linkedin?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=linkedin + [twitter]: https://cpco.io/twitter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=twitter + [testimonial]: https://cpco.io/leave-testimonial?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=testimonial + [office_hours]: https://cloudposse.com/office-hours?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=office_hours + [newsletter]: https://cpco.io/newsletter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=newsletter + [discourse]: https://ask.sweetops.com/?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=discourse + [email]: https://cpco.io/email?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=email + [commercial_support]: https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=commercial_support + [we_love_open_source]: https://cpco.io/we-love-open-source?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=we_love_open_source + [terraform_modules]: https://cpco.io/terraform-modules?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=terraform_modules + [readme_header_img]: https://cloudposse.com/readme/header/img + [readme_header_link]: https://cloudposse.com/readme/header/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_header_link + [readme_footer_img]: https://cloudposse.com/readme/footer/img + [readme_footer_link]: https://cloudposse.com/readme/footer/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_footer_link + [readme_commercial_support_img]: https://cloudposse.com/readme/commercial-support/img + [readme_commercial_support_link]: https://cloudposse.com/readme/commercial-support/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_commercial_support_link + [share_twitter]: https://twitter.com/intent/tweet/?text=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_linkedin]: https://www.linkedin.com/shareArticle?mini=true&title=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_reddit]: https://reddit.com/submit/?url=https://github.com/cloudposse/terraform-null-label + [share_facebook]: https://facebook.com/sharer/sharer.php?u=https://github.com/cloudposse/terraform-null-label + [share_googleplus]: https://plus.google.com/share?url=https://github.com/cloudposse/terraform-null-label + [share_email]: mailto:?subject=terraform-null-label&body=https://github.com/cloudposse/terraform-null-label + [beacon]: https://ga-beacon.cloudposse.com/UA-76589703-4/cloudposse/terraform-null-label?pixel&cs=github&cm=readme&an=terraform-null-label diff --git a/.terraform/modules/datadog_integration2.this/README.yaml b/.terraform/modules/datadog_integration2.this/README.yaml new file mode 100755 index 0000000..42bdb84 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/README.yaml @@ -0,0 +1,618 @@ +name: terraform-null-label +tags: +- aws +- terraform +- terraform-modules +- naming-convention +- name +- namespace +- stage +categories: +- terraform-modules/supported +license: APACHE2 +github_repo: cloudposse/terraform-null-label +badges: +- name: Latest Release + image: https://img.shields.io/github/release/cloudposse/terraform-null-label.svg + url: https://github.com/cloudposse/terraform-null-label/releases/latest +- name: Slack Community + image: https://slack.cloudposse.com/badge.svg + url: https://slack.cloudposse.com +related: +- name: terraform-terraform-label + description: Terraform Module to define a consistent naming convention by (namespace, + environment, stage, name, [attributes]) + url: https://github.com/cloudposse/terraform-terraform-label +description: |- + Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + + This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. + However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). + So if you prefer the term `stage` to `environment` + you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. + - If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. + - If you want the attributes in a different order, you can specify that, too, with the `label_order` list. + - You can set a maximum length for the name, and the module will create a unique name that fits within that length. + - You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. + - The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + + It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. + For example, if you have 10 instances, there should be 10 different labels. + However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + + All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + + **NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. + With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + + - Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. + - Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. + - Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. +usage: |- + ### Defaults + + Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. + The context object is a single object that contains all the input values for `terraform-null-label`. + However, each input value can also be specified individually by name as a standard Terraform variable, + and the value of those variables, when set to something other than `null`, will override the value + in the context object. In order to allow chaining of these objects, where the context object input to one + module is transformed and passed to the next module, all the variables default to `null` or empty collections. + The actual default values used when nothing is explicitly set are describe in the documentation below. + + For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, + `terraform-null-label` will actually use the default delimiter `-` (hyphen). + + A non-obvious but intentional consequence of this design is that once a module sets a non-default value, + future modules in the chain cannot reset the value back to the original default. Insted, the new setting + becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, + so once a tag is added, it will remain in the tag set and cannot be removed, although its value can + be overwritten. + + ### Simple Example + + ```hcl + module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + ``` + + This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` + (you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + + Now reference the label when creating an instance: + + ```hcl + resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags + } + ``` + + Or define a security group: + + ```hcl + resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + } + ``` + + + ### Advanced Example + + Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + + ```hcl + module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] + } + + module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] + } + ``` + +
+ + ### Advanced Example 2 + + Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + + ```hcl + tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } + ] + ``` + + Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + + ```hcl + ################################ + # terraform-null-label example # + ################################ + module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } + } + + ####################### + # Launch template # + ####################### + resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } + } + + ###################### + # Autoscaling group # + ###################### + resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps + } + ``` + +
+ + ### Advanced Example 3 + + See [complete example](./examples/complete) for even more examples. + + This example shows how you can pass the `context` output of one label module to the next label_module, + allowing you to create one label that has the base set of values, and then creating every extra label + as a derivative of that. + +
Click to show + + ```hcl + module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } + } + + module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } + } + + module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } + } + ``` + + This creates label outputs like this: + + ```hcl + label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" + } + label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } + } + label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + } + label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" + } + label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } + } + label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" + } + label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, + ] + label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" + } + label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } + } + label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + } + label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + + ``` + +
+ +include: +- docs/targets.md +- docs/terraform.md +contributors: +- name: Erik Osterman + github: osterman +- name: Andriy Knysh + github: aknysh +- name: Igor Rodionov + github: goruha +- name: Sergey Vasilyev + github: s2504s +- name: Michael Pereira + github: MichaelPereira +- name: Jamie Nelson + github: Jamie-BitFlight +- name: Vladimir + github: SweetOps +- name: Daren Desjardins + github: darend +- name: Maarten van der Hoef + github: maartenvanderhoef +- name: Adam Tibbing + github: tibbing diff --git a/.terraform/modules/datadog_integration2.this/docs/targets.md b/.terraform/modules/datadog_integration2.this/docs/targets.md new file mode 100755 index 0000000..3dce8b3 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/docs/targets.md @@ -0,0 +1,12 @@ + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + diff --git a/.terraform/modules/datadog_integration2.this/docs/terraform.md b/.terraform/modules/datadog_integration2.this/docs/terraform.md new file mode 100755 index 0000000..d4f48f4 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/docs/terraform.md @@ -0,0 +1,54 @@ + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + diff --git a/.terraform/modules/datadog_integration2.this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars b/.terraform/modules/datadog_integration2.this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars new file mode 100755 index 0000000..f7c725f --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars @@ -0,0 +1,12 @@ +namespace = "eg" +stage = "prod" +name = "app" + +tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" +} + +additional_tag_map = { + propagate_at_launch = "true" +} diff --git a/.terraform/modules/datadog_integration2.this/examples/autoscalinggroup/context.tf b/.terraform/modules/datadog_integration2.this/examples/autoscalinggroup/context.tf new file mode 100755 index 0000000..b97f05f --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/autoscalinggroup/context.tf @@ -0,0 +1,216 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration2.this/examples/autoscalinggroup/main.tf b/.terraform/modules/datadog_integration2.this/examples/autoscalinggroup/main.tf new file mode 100755 index 0000000..f0d3aa6 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/autoscalinggroup/main.tf @@ -0,0 +1,104 @@ +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + + context = module.this.context +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template { + id = aws_launch_template.default.id + version = "$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} + +################################ +# Provider # +################################ +provider "aws" { + region = "eu-west-1" + + # Make it faster by skipping unneeded checks here + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +############################################################## +# Data sources to get VPC, subnets and security group details +############################################################## +data "aws_vpc" "default" { + default = true +} + +data "aws_subnet_ids" "all" { + vpc_id = data.aws_vpc.default.id +} + +data "aws_security_group" "default" { + vpc_id = data.aws_vpc.default.id + name = "default" +} + +data "aws_ami" "amazon_linux" { + most_recent = true + + owners = ["amazon"] + + filter { + name = "name" + + values = [ + "amzn-ami-hvm-*-x86_64-gp2", + ] + } + + filter { + name = "owner-alias" + + values = [ + "amazon", + ] + } +} + diff --git a/.terraform/modules/datadog_integration2.this/examples/autoscalinggroup/outputs.tf b/.terraform/modules/datadog_integration2.this/examples/autoscalinggroup/outputs.tf new file mode 100755 index 0000000..f8fcce5 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/autoscalinggroup/outputs.tf @@ -0,0 +1,12 @@ +# terraform-null-label example used here: Output list of tags applied in each format +output "tags_as_list_of_maps" { + value = module.label.tags_as_list_of_maps +} + +output "tags" { + value = module.label.tags +} + +output "id" { + value = module.label.id +} diff --git a/.terraform/modules/datadog_integration2.this/examples/autoscalinggroup/versions.tf b/.terraform/modules/datadog_integration2.this/examples/autoscalinggroup/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/autoscalinggroup/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration2.this/examples/complete/complete.auto.tfvars b/.terraform/modules/datadog_integration2.this/examples/complete/complete.auto.tfvars new file mode 100755 index 0000000..e7bc519 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/complete/complete.auto.tfvars @@ -0,0 +1,10 @@ +namespace = "cp" +environment = "uw2" +stage = "prd" +name = "null-label" + +delimiter = "" +id_length_limit = 6 + +label_key_case = "lower" +label_value_case = "upper" diff --git a/.terraform/modules/datadog_integration2.this/examples/complete/context.tf b/.terraform/modules/datadog_integration2.this/examples/complete/context.tf new file mode 100755 index 0000000..973d4dc --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/complete/context.tf @@ -0,0 +1,217 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration2.this/examples/complete/label1.tf b/.terraform/modules/datadog_integration2.this/examples/complete/label1.tf new file mode 100755 index 0000000..8da353b --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/complete/label1.tf @@ -0,0 +1,42 @@ +module "label1" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label1" { + value = { + id = module.label1.id + name = module.label1.name + namespace = module.label1.namespace + stage = module.label1.stage + attributes = module.label1.attributes + delimiter = module.label1.delimiter + } +} + +output "label1_tags" { + value = module.label1.tags +} + +output "label1_context" { + value = module.label1.context +} + +output "label1_normalized_context" { + value = module.label1.normalized_context +} + + + diff --git a/.terraform/modules/datadog_integration2.this/examples/complete/label1t1.tf b/.terraform/modules/datadog_integration2.this/examples/complete/label1t1.tf new file mode 100755 index 0000000..2bcb362 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/complete/label1t1.tf @@ -0,0 +1,18 @@ +module "label1t1" { + source = "../../" + + id_length_limit = 28 + + context = module.label1.context +} + +output "label1t1" { + value = { + id = module.label1t1.id + id_full = module.label1t1.id_full + } +} + +output "label1t1_tags" { + value = module.label1t1.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration2.this/examples/complete/label1t2.tf b/.terraform/modules/datadog_integration2.this/examples/complete/label1t2.tf new file mode 100755 index 0000000..5df651e --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/complete/label1t2.tf @@ -0,0 +1,18 @@ +module "label1t2" { + source = "../../" + + id_length_limit = 29 + + context = module.label1.context +} + +output "label1t2" { + value = { + id = module.label1t2.id + id_full = module.label1t2.id_full + } +} + +output "label1t2_tags" { + value = module.label1t2.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration2.this/examples/complete/label2.tf b/.terraform/modules/datadog_integration2.this/examples/complete/label2.tf new file mode 100755 index 0000000..faf7450 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/complete/label2.tf @@ -0,0 +1,42 @@ +module "label2" { + source = "../../" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + regex_replace_chars = "/[^a-zA-Z0-9-+]/" + + additional_tag_map = { + propagate_at_launch = "true" + additional_tag = "yes" + } + + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +output "label2" { + value = { + id = module.label2.id + name = module.label2.name + namespace = module.label2.namespace + stage = module.label2.stage + attributes = module.label2.attributes + delimiter = module.label2.delimiter + } +} + +output "label2_tags" { + value = module.label2.tags +} + +output "label2_tags_as_list_of_maps" { + value = module.label2.tags_as_list_of_maps +} + +output "label2_context" { + value = module.label2.context +} diff --git a/.terraform/modules/datadog_integration2.this/examples/complete/label3c.tf b/.terraform/modules/datadog_integration2.this/examples/complete/label3c.tf new file mode 100755 index 0000000..338a636 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/complete/label3c.tf @@ -0,0 +1,36 @@ +module "label3c" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3c" { + value = { + id = module.label3c.id + name = module.label3c.name + namespace = module.label3c.namespace + stage = module.label3c.stage + attributes = module.label3c.attributes + delimiter = module.label3c.delimiter + } +} + +output "label3c_tags" { + value = module.label3c.tags +} + +output "label3c_context" { + value = module.label3c.context +} + +output "label3c_normalized_context" { + value = module.label3c.normalized_context +} diff --git a/.terraform/modules/datadog_integration2.this/examples/complete/label3n.tf b/.terraform/modules/datadog_integration2.this/examples/complete/label3n.tf new file mode 100755 index 0000000..ca51282 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/complete/label3n.tf @@ -0,0 +1,36 @@ +module "label3n" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.normalized_context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3n" { + value = { + id = module.label3n.id + name = module.label3n.name + namespace = module.label3n.namespace + stage = module.label3n.stage + attributes = module.label3n.attributes + delimiter = module.label3n.delimiter + } +} + +output "label3n_tags" { + value = module.label3n.tags +} + +output "label3n_context" { + value = module.label3n.context +} + +output "label3n_normalized_context" { + value = module.label3n.normalized_context +} diff --git a/.terraform/modules/datadog_integration2.this/examples/complete/label4.tf b/.terraform/modules/datadog_integration2.this/examples/complete/label4.tf new file mode 100755 index 0000000..74e3ca1 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/complete/label4.tf @@ -0,0 +1,34 @@ +module "label4" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + name = "Example Cluster" + attributes = ["big", "fat", "honking", "cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label4" { + value = { + id = module.label4.id + name = module.label4.name + namespace = module.label4.namespace + stage = module.label4.stage + attributes = module.label4.attributes + delimiter = module.label4.delimiter + } +} + +output "label4_tags" { + value = module.label4.tags +} + +output "label4_context" { + value = module.label4.context +} diff --git a/.terraform/modules/datadog_integration2.this/examples/complete/label5.tf b/.terraform/modules/datadog_integration2.this/examples/complete/label5.tf new file mode 100755 index 0000000..0f0a76e --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/complete/label5.tf @@ -0,0 +1,33 @@ +module "label5" { + source = "../../" + enabled = false + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + } +} + +output "label5" { + value = { + id = module.label5.id + name = module.label5.name + namespace = module.label5.namespace + stage = module.label5.stage + attributes = module.label5.attributes + delimiter = module.label5.delimiter + } +} + +output "label5_tags" { + value = module.label5.tags +} + +output "label5_context" { + value = module.label5.context +} diff --git a/.terraform/modules/datadog_integration2.this/examples/complete/label6f.tf b/.terraform/modules/datadog_integration2.this/examples/complete/label6f.tf new file mode 100755 index 0000000..1ce1bab --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/complete/label6f.tf @@ -0,0 +1,20 @@ +module "label6f" { + source = "../../" + + delimiter = "~" + id_length_limit = 0 + + # Use values from tfvars + context = module.this.context +} + +output "label6f" { + value = { + id = module.label6f.id + id_full = module.label6f.id_full + } +} + +output "label6f_tags" { + value = module.label6f.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration2.this/examples/complete/label6t.tf b/.terraform/modules/datadog_integration2.this/examples/complete/label6t.tf new file mode 100755 index 0000000..b5d9bc1 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/complete/label6t.tf @@ -0,0 +1,19 @@ +module "label6t" { + source = "../../" + + # Use values from tfvars, + # specifically: complete.auto.tfvars + context = module.this.context +} + +output "label6t" { + value = { + id = module.label6t.id + id_full = module.label6t.id_full + id_length_limit = module.this.context.id_length_limit + } +} + +output "label6t_tags" { + value = module.label6t.tags +} \ No newline at end of file diff --git a/.terraform/modules/datadog_integration2.this/examples/complete/label7.tf b/.terraform/modules/datadog_integration2.this/examples/complete/label7.tf new file mode 100755 index 0000000..bb365d4 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/complete/label7.tf @@ -0,0 +1,44 @@ +module "label7a" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + } +} + +module "label7" { + source = "../../" + + attributes = ["nodegroup"] + + context = module.label7a.context +} + + +output "label7" { + value = { + id = module.label7.id + name = module.label7.name + namespace = module.label7.namespace + stage = module.label7.stage + attributes = module.label7.attributes + delimiter = module.label7.delimiter + } +} + +output "label7_id" { + value = module.label7.id +} + +output "label7_attributes" { + value = module.label7.attributes +} + +output "label7_context" { + value = module.label7.context +} diff --git a/.terraform/modules/datadog_integration2.this/examples/complete/label8d.tf b/.terraform/modules/datadog_integration2.this/examples/complete/label8d.tf new file mode 100755 index 0000000..4252419 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/complete/label8d.tf @@ -0,0 +1,44 @@ +module "label8d" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8d_context" { + source = "../../" + + context = module.label8d.context +} + +output "label8d_context_id" { + value = module.label8d_context.id +} + +output "label8d_context_context" { + value = module.label8d_context.context +} + +output "label8d_context_tags" { + value = module.label8d_context.tags +} + +output "label8d_id" { + value = module.label8d.id +} + +output "label8d_context" { + value = module.label8d.context +} + +output "label8d_tags" { + value = module.label8d.tags +} diff --git a/.terraform/modules/datadog_integration2.this/examples/complete/label8dcd.tf b/.terraform/modules/datadog_integration2.this/examples/complete/label8dcd.tf new file mode 100755 index 0000000..ccdae21 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/complete/label8dcd.tf @@ -0,0 +1,24 @@ +module "label8dcd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "x" +} + +module "label8dcd_context" { + source = "../../" + + context = module.label8dcd.context +} + +output "label8dcd_context_id" { + value = module.label8dcd_context.id +} + +output "label8dcd_id" { + value = module.label8dcd.id +} diff --git a/.terraform/modules/datadog_integration2.this/examples/complete/label8dnd.tf b/.terraform/modules/datadog_integration2.this/examples/complete/label8dnd.tf new file mode 100755 index 0000000..2edb378 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/complete/label8dnd.tf @@ -0,0 +1,24 @@ +module "label8dnd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "" +} + +module "label8dnd_context" { + source = "../../" + + context = module.label8dnd.context +} + +output "label8dnd_context_id" { + value = module.label8dnd_context.id +} + +output "label8dnd_id" { + value = module.label8dnd.id +} diff --git a/.terraform/modules/datadog_integration2.this/examples/complete/label8l.tf b/.terraform/modules/datadog_integration2.this/examples/complete/label8l.tf new file mode 100755 index 0000000..7462f9e --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/complete/label8l.tf @@ -0,0 +1,46 @@ +module "label8l" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "lower" + label_value_case = "lower" + + tags = { + "kubernetes.io/cluster/" = "shared" + "upperTEST" = "testUPPER" + } +} + +module "label8l_context" { + source = "../../" + + context = module.label8l.context +} + +output "label8l_context_id" { + value = module.label8l_context.id +} + +output "label8l_context_context" { + value = module.label8l_context.context +} + +output "label8l_context_tags" { + value = module.label8l_context.tags +} + +output "label8l_id" { + value = module.label8l.id +} + +output "label8l_context" { + value = module.label8l.context +} + +output "label8l_tags" { + value = module.label8l.tags +} diff --git a/.terraform/modules/datadog_integration2.this/examples/complete/label8n.tf b/.terraform/modules/datadog_integration2.this/examples/complete/label8n.tf new file mode 100755 index 0000000..fd4ad57 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/complete/label8n.tf @@ -0,0 +1,45 @@ +module "label8n" { + source = "../../" + + enabled = true + namespace = "EG" + environment = "demo" + name = "blue" + attributes = ["eks", "ClusteR"] + delimiter = "-" + label_value_case = "none" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8n_context" { + source = "../../" + + context = module.label8n.context +} + +output "label8n_context_id" { + value = module.label8n_context.id +} + +output "label8n_context_context" { + value = module.label8n_context.context +} + +output "label8n_context_tags" { + value = module.label8n_context.tags +} + +output "label8n_id" { + value = module.label8n.id +} + +output "label8n_context" { + value = module.label8n.context +} + +output "label8n_tags" { + value = module.label8n.tags +} diff --git a/.terraform/modules/datadog_integration2.this/examples/complete/label8t.tf b/.terraform/modules/datadog_integration2.this/examples/complete/label8t.tf new file mode 100755 index 0000000..cb54c7a --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/complete/label8t.tf @@ -0,0 +1,45 @@ +module "label8t" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["EKS", "cluster"] + delimiter = "-" + label_key_case = "title" + label_value_case = "title" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8t_context" { + source = "../../" + + context = module.label8t.context +} + +output "label8t_context_id" { + value = module.label8t_context.id +} + +output "label8t_context_context" { + value = module.label8t_context.context +} + +output "label8t_context_tags" { + value = module.label8t_context.tags +} + +output "label8t_id" { + value = module.label8t.id +} + +output "label8t_context" { + value = module.label8t.context +} + +output "label8t_tags" { + value = module.label8t.tags +} diff --git a/.terraform/modules/datadog_integration2.this/examples/complete/label8u.tf b/.terraform/modules/datadog_integration2.this/examples/complete/label8u.tf new file mode 100755 index 0000000..499535b --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/complete/label8u.tf @@ -0,0 +1,50 @@ +module "label8u" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "upper" + label_value_case = "upper" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8u_context" { + source = "../../" + + context = module.label8u.context +} + +output "label8u_context_id" { + value = module.label8u_context.id +} + +output "label8u_context_context" { + value = module.label8u_context.context +} + +// debug +output "label8u_context_normalized_context" { + value = module.label8u_context.normalized_context +} + +output "label8u_context_tags" { + value = module.label8u_context.tags +} + +output "label8u_id" { + value = module.label8u.id +} + +output "label8u_context" { + value = module.label8u.context +} + +output "label8u_tags" { + value = module.label8u.tags +} diff --git a/.terraform/modules/datadog_integration2.this/examples/complete/versions.tf b/.terraform/modules/datadog_integration2.this/examples/complete/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/examples/complete/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/datadog_integration2.this/exports/context.tf b/.terraform/modules/datadog_integration2.this/exports/context.tf new file mode 100755 index 0000000..81f99b4 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/exports/context.tf @@ -0,0 +1,202 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/datadog_integration2.this/main.tf b/.terraform/modules/datadog_integration2.this/main.tf new file mode 100755 index 0000000..0deda2b --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/main.tf @@ -0,0 +1,146 @@ +locals { + + defaults = { + label_order = ["namespace", "environment", "stage", "name", "attributes"] + regex_replace_chars = "/[^-a-zA-Z0-9]/" + delimiter = "-" + replacement = "" + id_length_limit = 0 + id_hash_length = 5 + label_key_case = "title" + label_value_case = "lower" + } + + # So far, we have decided not to allow overriding replacement or id_hash_length + replacement = local.defaults.replacement + id_hash_length = local.defaults.id_hash_length + + # The values provided by variables supersede the values inherited from the context object, + # except for tags and attributes which are merged. + input = { + # It would be nice to use coalesce here, but we cannot, because it + # is an error for all the arguments to coalesce to be empty. + enabled = var.enabled == null ? var.context.enabled : var.enabled + namespace = var.namespace == null ? var.context.namespace : var.namespace + environment = var.environment == null ? var.context.environment : var.environment + stage = var.stage == null ? var.context.stage : var.stage + name = var.name == null ? var.context.name : var.name + delimiter = var.delimiter == null ? var.context.delimiter : var.delimiter + # modules tack on attributes (passed by var) to the end of the list (passed by context) + attributes = compact(distinct(concat(coalesce(var.context.attributes, []), coalesce(var.attributes, [])))) + tags = merge(var.context.tags, var.tags) + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + label_order = var.label_order == null ? var.context.label_order : var.label_order + regex_replace_chars = var.regex_replace_chars == null ? var.context.regex_replace_chars : var.regex_replace_chars + id_length_limit = var.id_length_limit == null ? var.context.id_length_limit : var.id_length_limit + label_key_case = var.label_key_case == null ? lookup(var.context, "label_key_case", null) : var.label_key_case + label_value_case = var.label_value_case == null ? lookup(var.context, "label_value_case", null) : var.label_value_case + } + + + enabled = local.input.enabled + regex_replace_chars = coalesce(local.input.regex_replace_chars, local.defaults.regex_replace_chars) + + # string_label_names are names of inputs that are strings (not list of strings) used as labels + string_label_names = ["name", "namespace", "environment", "stage"] + normalized_labels = { for k in local.string_label_names : k => + local.input[k] == null ? "" : replace(local.input[k], local.regex_replace_chars, local.replacement) + } + normalized_attributes = compact(distinct([for v in local.input.attributes : replace(v, local.regex_replace_chars, local.replacement)])) + + formatted_labels = { for k in local.string_label_names : k => local.label_value_case == "none" ? local.normalized_labels[k] : + local.label_value_case == "title" ? title(lower(local.normalized_labels[k])) : + local.label_value_case == "upper" ? upper(local.normalized_labels[k]) : lower(local.normalized_labels[k]) + } + + attributes = compact(distinct([ + for v in local.normalized_attributes : (local.label_value_case == "none" ? v : + local.label_value_case == "title" ? title(lower(v)) : + local.label_value_case == "upper" ? upper(v) : lower(v)) + ])) + + name = local.formatted_labels["name"] + namespace = local.formatted_labels["namespace"] + environment = local.formatted_labels["environment"] + stage = local.formatted_labels["stage"] + + delimiter = local.input.delimiter == null ? local.defaults.delimiter : local.input.delimiter + label_order = local.input.label_order == null ? local.defaults.label_order : coalescelist(local.input.label_order, local.defaults.label_order) + id_length_limit = local.input.id_length_limit == null ? local.defaults.id_length_limit : local.input.id_length_limit + label_key_case = local.input.label_key_case == null ? local.defaults.label_key_case : local.input.label_key_case + label_value_case = local.input.label_value_case == null ? local.defaults.label_value_case : local.input.label_value_case + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + + tags = merge(local.generated_tags, local.input.tags) + + tags_as_list_of_maps = flatten([ + for key in keys(local.tags) : merge( + { + key = key + value = local.tags[key] + }, var.additional_tag_map) + ]) + + tags_context = { + # For AWS we need `Name` to be disambiguated since it has a special meaning + name = local.id + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = local.id_context.attributes + } + + generated_tags = { + for l in keys(local.tags_context) : + local.label_key_case == "upper" ? upper(l) : ( + local.label_key_case == "lower" ? lower(l) : title(lower(l)) + ) => local.tags_context[l] if length(local.tags_context[l]) > 0 + } + + id_context = { + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = join(local.delimiter, local.attributes) + } + + labels = [for l in local.label_order : local.id_context[l] if length(local.id_context[l]) > 0] + + id_full = join(local.delimiter, local.labels) + # Create a truncated ID if needed + delimiter_length = length(local.delimiter) + # Calculate length of normal part of ID, leaving room for delimiter and hash + id_truncated_length_limit = local.id_length_limit - (local.id_hash_length + local.delimiter_length) + # Truncate the ID and ensure a single (not double) trailing delimiter + id_truncated = local.id_truncated_length_limit <= 0 ? "" : "${trimsuffix(substr(local.id_full, 0, local.id_truncated_length_limit), local.delimiter)}${local.delimiter}" + # Support usages that disallow numeric characters. Would prefer tr 0-9 q-z but Terraform does not support it. + id_hash_plus = "${md5(local.id_full)}qrstuvwxyz" + id_hash_case = local.label_value_case == "title" ? title(local.id_hash_plus) : local.label_value_case == "upper" ? upper(local.id_hash_plus) : local.label_value_case == "lower" ? lower(local.id_hash_plus) : local.id_hash_plus + id_hash = replace(local.id_hash_case, local.regex_replace_chars, local.replacement) + # Create the short ID by adding a hash to the end of the truncated ID + id_short = substr("${local.id_truncated}${local.id_hash}", 0, local.id_length_limit) + id = local.id_length_limit != 0 && length(local.id_full) > local.id_length_limit ? local.id_short : local.id_full + + + # Context of this label to pass to other label modules + output_context = { + enabled = local.enabled + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + delimiter = local.delimiter + attributes = local.attributes + tags = local.tags + additional_tag_map = local.additional_tag_map + label_order = local.label_order + regex_replace_chars = local.regex_replace_chars + id_length_limit = local.id_length_limit + label_key_case = local.label_key_case + label_value_case = local.label_value_case + } + +} diff --git a/.terraform/modules/datadog_integration2.this/outputs.tf b/.terraform/modules/datadog_integration2.this/outputs.tf new file mode 100755 index 0000000..87ad1be --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/outputs.tf @@ -0,0 +1,88 @@ +output "id" { + value = local.enabled ? local.id : "" + description = "Disambiguated ID restricted to `id_length_limit` characters in total" +} + +output "id_full" { + value = local.enabled ? local.id_full : "" + description = "Disambiguated ID not restricted in length" +} + +output "enabled" { + value = local.enabled + description = "True if module is enabled, false otherwise" +} + +output "namespace" { + value = local.enabled ? local.namespace : "" + description = "Normalized namespace" +} + +output "environment" { + value = local.enabled ? local.environment : "" + description = "Normalized environment" +} + +output "name" { + value = local.enabled ? local.name : "" + description = "Normalized name" +} + +output "stage" { + value = local.enabled ? local.stage : "" + description = "Normalized stage" +} + +output "delimiter" { + value = local.enabled ? local.delimiter : "" + description = "Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes`" +} + +output "attributes" { + value = local.enabled ? local.attributes : [] + description = "List of attributes" +} + +output "tags" { + value = local.enabled ? local.tags : {} + description = "Normalized Tag map" +} + +output "additional_tag_map" { + value = local.additional_tag_map + description = "The merged additional_tag_map" +} + +output "label_order" { + value = local.label_order + description = "The naming order actually used to create the ID" +} + +output "regex_replace_chars" { + value = local.regex_replace_chars + description = "The regex_replace_chars actually used to create the ID" +} + +output "id_length_limit" { + value = local.id_length_limit + description = "The id_length_limit actually used to create the ID, with `0` meaning unlimited" +} + +output "tags_as_list_of_maps" { + value = local.tags_as_list_of_maps + description = "Additional tags as a list of maps, which can be used in several AWS resources" +} + +output "normalized_context" { + value = local.output_context + description = "Normalized context of this module" +} + +output "context" { + value = local.input + description = <<-EOT + Merged but otherwise unmodified input to this module, to be used as context input to other modules. + Note: this version will have null values as defaults, not the values actually used as defaults. +EOT +} + diff --git a/.terraform/modules/datadog_integration2.this/test/Makefile b/.terraform/modules/datadog_integration2.this/test/Makefile new file mode 100755 index 0000000..ea15d62 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/test/Makefile @@ -0,0 +1,43 @@ +TEST_HARNESS ?= https://github.com/cloudposse/test-harness.git +TEST_HARNESS_BRANCH ?= master +TEST_HARNESS_PATH = $(realpath .test-harness) +BATS_ARGS ?= --tap +BATS_LOG ?= test.log + +# Define a macro to run the tests +define RUN_TESTS +@echo "Running tests in $(1)" +@cd $(1) && bats $(BATS_ARGS) $(addsuffix .bats,$(addprefix $(TEST_HARNESS_PATH)/test/terraform/,$(TESTS))) +endef + +default: all + +-include Makefile.* + +## Provision the test-harnesss +.test-harness: + [ -d $@ ] || git clone --depth=1 -b $(TEST_HARNESS_BRANCH) $(TEST_HARNESS) $@ + +## Initialize the tests +init: .test-harness + +## Install all dependencies (OS specific) +deps:: + @exit 0 + +## Clean up the test harness +clean: + [ "$(TEST_HARNESS_PATH)" == "/" ] || rm -rf $(TEST_HARNESS_PATH) + +## Run all tests +all: module examples/complete + +## Run basic sanity checks against the module itself +module: export TESTS ?= installed lint get-modules module-pinning get-plugins provider-pinning validate terraform-docs input-descriptions output-descriptions +module: deps + $(call RUN_TESTS, ../) + +## Run tests against example +examples/complete: export TESTS ?= installed lint get-modules get-plugins validate init plan apply +examples/complete: deps + $(call RUN_TESTS, ../$@) diff --git a/.terraform/modules/datadog_integration2.this/test/Makefile.alpine b/.terraform/modules/datadog_integration2.this/test/Makefile.alpine new file mode 100755 index 0000000..7925b18 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/test/Makefile.alpine @@ -0,0 +1,5 @@ +ifneq (,$(wildcard /sbin/apk)) +## Install all dependencies for alpine +deps:: init + @apk add --update terraform-docs@cloudposse json2hcl@cloudposse +endif diff --git a/.terraform/modules/datadog_integration2.this/test/src/Makefile b/.terraform/modules/datadog_integration2.this/test/src/Makefile new file mode 100755 index 0000000..b772822 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/test/src/Makefile @@ -0,0 +1,30 @@ +export TF_CLI_ARGS_init ?= -get-plugins=true +export TERRAFORM_VERSION ?= $(shell curl -s https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r -M '.current_version' | cut -d. -f1-2) + +.DEFAULT_GOAL : all +.PHONY: all + +## Default target +all: test + +.PHONY : init +## Initialize tests +init: + @exit 0 + +.PHONY : test +## Run tests +test: init + go mod download + go test -v -timeout 60m -run TestExamplesComplete + +## Run tests in docker container +docker/test: + docker run --name terratest --rm -it -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e GITHUB_TOKEN \ + -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" \ + -v $(CURDIR)/../../:/module/ cloudposse/test-harness:latest -C /module/test/src test + +.PHONY : clean +## Clean up files +clean: + rm -rf ../../examples/complete/*.tfstate* diff --git a/.terraform/modules/datadog_integration2.this/test/src/examples_complete_test.go b/.terraform/modules/datadog_integration2.this/test/src/examples_complete_test.go new file mode 100755 index 0000000..156e293 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/test/src/examples_complete_test.go @@ -0,0 +1,293 @@ +package test + +import ( + "fmt" + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" + "github.com/qdm12/reprint" + "github.com/stretchr/testify/assert" +) + +type NLContext struct { + AdditionalTagMap map[string]string `json:"additional_tag_map"` + Attributes []string `json:"attributes"` + Delimiter interface{} `json:"delimiter"` + Enabled bool `json:"enabled"` + Environment interface{} `json:"environment"` + LabelOrder []string `json:"label_order"` + Name interface{} `json:"name"` + Namespace interface{} `json:"namespace"` + RegexReplaceChars interface{} `json:"regex_replace_chars"` + Stage interface{} `json:"stage"` + Tags map[string]string `json:"tags"` +} + +// Test the Terraform module in examples/complete using Terratest. +func TestExamplesComplete(t *testing.T) { + t.Parallel() + + terraformOptions := &terraform.Options{ + // The path to where our Terraform code is located + TerraformDir: "../../examples/complete", + Upgrade: true, + } + + // At the end of the test, run `terraform destroy` to clean up any resources that were created + defer terraform.Destroy(t, terraformOptions) + + // This will run `terraform init` and `terraform apply` and fail the test if there are any errors + terraform.InitAndApply(t, terraformOptions) + + expectedLabel1Context := NLContext{ + Enabled: true, + Namespace: "CloudPosse", + Environment: "UAT", + Stage: "build", + Name: "Winston Churchroom", + Attributes: []string{"fire", "water", "earth", "air"}, + Delimiter: "-", + LabelOrder: []string{"name", "environment", "stage", "attributes"}, + Tags: map[string]string{ + "City": "Dublin", + "Environment": "Private", + }, + AdditionalTagMap: map[string]string{}, + } + + var expectedLabel1NormalizedContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel1NormalizedContext) + expectedLabel1NormalizedContext.Namespace = "cloudposse" + expectedLabel1NormalizedContext.Environment = "uat" + expectedLabel1NormalizedContext.Name = "winstonchurchroom" + expectedLabel1NormalizedContext.RegexReplaceChars = "/[^-a-zA-Z0-9]/" + expectedLabel1NormalizedContext.Tags = map[string]string{ + "City": "Dublin", + "Environment": "Private", + "Namespace": "cloudposse", + "Stage": "build", + "Name": "winstonchurchroom-uat-build-fire-water-earth-air", + "Attributes": "fire-water-earth-air", + } + + var label1NormalizedContext, label1Context NLContext + // Run `terraform output` to get the value of an output variable + label1 := terraform.OutputMap(t, terraformOptions, "label1") + label1Tags := terraform.OutputMap(t, terraformOptions, "label1_tags") + terraform.OutputStruct(t, terraformOptions, "label1_normalized_context", &label1NormalizedContext) + terraform.OutputStruct(t, terraformOptions, "label1_context", &label1Context) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1["id"]) + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1Tags["Name"]) + assert.Equal(t, "Dublin", label1Tags["City"]) + assert.Equal(t, "Private", label1Tags["Environment"]) + assert.Equal(t, expectedLabel1NormalizedContext, label1NormalizedContext) + assert.Equal(t, expectedLabel1Context, label1Context) + + label1t1 := terraform.OutputMap(t, terraformOptions, "label1t1") + label1t1Tags := terraform.OutputMap(t, terraformOptions, "label1t1_tags") + assert.Equal(t, "winstonchurchroom-uat-6a0b34", label1t1["id"], + "Extra hash character should be added when trailing delimiter is removed") + assert.Equal(t, label1["id"], label1t1["id_full"], "id_full should not be truncated") + assert.Equal(t, label1t1["id"], label1t1Tags["Name"], "Name tag should match ID") + + label1t2 := terraform.OutputMap(t, terraformOptions, "label1t2") + label1t2Tags := terraform.OutputMap(t, terraformOptions, "label1t2_tags") + assert.Equal(t, "winstonchurchroom-uat-b-6a0b3", label1t2["id"]) + assert.Equal(t, label1t2["id"], label1t2Tags["Name"], "Name tag should match ID") + + // Run `terraform output` to get the value of an output variable + label2 := terraform.OutputMap(t, terraformOptions, "label2") + label2Tags := terraform.OutputMap(t, terraformOptions, "label2_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2["id"]) + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2Tags["Name"]) + assert.Equal(t, "London", label2Tags["City"]) + assert.Equal(t, "Public", label2Tags["Environment"]) + + var expectedLabel3cContext, label3cContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel3cContext) + expectedLabel3cContext.Name = "Starfish" + expectedLabel3cContext.Stage = "release" + expectedLabel3cContext.Delimiter = "." + expectedLabel3cContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3cContext.Tags["Eat"] = "Carrot" + expectedLabel3cContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3c := terraform.OutputMap(t, terraformOptions, "label3c") + label3cTags := terraform.OutputMap(t, terraformOptions, "label3c_tags") + terraform.OutputStruct(t, terraformOptions, "label3c_context", &label3cContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3c["id"]) + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3cTags["Name"]) + assert.Equal(t, expectedLabel3cContext, label3cContext) + + var expectedLabel3nContext, label3nContext NLContext + _ = reprint.FromTo(&expectedLabel1NormalizedContext, &expectedLabel3nContext) + expectedLabel3nContext.Name = "Starfish" + expectedLabel3nContext.Stage = "release" + expectedLabel3nContext.Delimiter = "." + expectedLabel3nContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3nContext.Tags["Eat"] = "Carrot" + expectedLabel3nContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3n := terraform.OutputMap(t, terraformOptions, "label3n") + label3nTags := terraform.OutputMap(t, terraformOptions, "label3n_tags") + terraform.OutputStruct(t, terraformOptions, "label3n_context", &label3nContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3n["id"]) + assert.Equal(t, label1Tags["Name"], label3nTags["Name"], + "Tag from label1 normalized context should overwrite label3n generated tag") + assert.Equal(t, expectedLabel3nContext, label3nContext) + + // Run `terraform output` to get the value of an output variable + label4 := terraform.OutputMap(t, terraformOptions, "label4") + label4Tags := terraform.OutputMap(t, terraformOptions, "label4_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4["id"]) + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4Tags["Name"]) + + // Run `terraform output` to get the value of an output variable + label5 := terraform.OutputMap(t, terraformOptions, "label5") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "", label5["id"]) + + label6f := terraform.OutputMap(t, terraformOptions, "label6f") + label6fTags := terraform.OutputMap(t, terraformOptions, "label6f_tags") + // Test of setting var.label_key_case = "lower", var.label_value_case = "upper" + assert.Equal(t, "CP~UW2~PRD~NULL-LABEL", label6f["id_full"]) + assert.Equal(t, label6f["id_full"], label6f["id"], "id should not be truncated") + assert.Equal(t, label6f["id"], label6fTags["name"], "Name tag should match ID") + + label6t := terraform.OutputMap(t, terraformOptions, "label6t") + label6tTags := terraform.OutputMap(t, terraformOptions, "label6t_tags") + assert.Equal(t, "CPUW2PRDNULL-LABEL", label6t["id_full"]) + assert.NotEqual(t, label6t["id_full"], label6t["id"], "id should be truncated") + assert.Equal(t, label6t["id"], label6tTags["name"], "Name tag should match ID") + assert.Equal(t, label6t["id_length_limit"], fmt.Sprintf("%d", len(label6t["id"])), + "Truncated ID length should equal length limit") + + label7 := terraform.OutputMap(t, terraformOptions, "label7") + assert.Equal(t, "eg-demo-blue-cluster-nodegroup", label7["id"], "var.attributes should be appended after context.attributes") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter=""` returns expected value of id, context id + label8dndID := terraform.Output(t, terraformOptions, "label8dnd_id") + label8dndContextID := terraform.Output(t, terraformOptions, "label8dnd_context_id") + assert.Equal(t, "egdemobluecluster", label8dndID) + assert.Equal(t, label8dndID, label8dndContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter="x"` returns expected value of id, context id + label8dcdID := terraform.Output(t, terraformOptions, "label8dcd_id") + label8dcdContextID := terraform.Output(t, terraformOptions, "label8dcd_context_id") + assert.Equal(t, "egxdemoxbluexcluster", label8dcdID) + assert.Equal(t, label8dcdID, label8dcdContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=lower` returns expected values of id, tags, context tags + label8dExpectedTags := map[string]string{ + "Attributes": "cluster", + "Environment": "demo", + "Name": "eg-demo-blue-cluster", + "Namespace": "eg", + "kubernetes.io/cluster/": "shared", + } + + label8dID := terraform.Output(t, terraformOptions, "label8d_id") + label8dContextID := terraform.Output(t, terraformOptions, "label8d_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8dID) + assert.Equal(t, label8dID, label8dContextID, "ID and context ID should be equal") + + label8dTags := terraform.OutputMap(t, terraformOptions, "label8d_tags") + label8dContextTags := terraform.OutputMap(t, terraformOptions, "label8d_context_tags") + + assert.Exactly(t, label8dExpectedTags, label8dTags, "generated tags are different from expected") + assert.Exactly(t, label8dTags, label8dContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=lower` and `label_value_case=lower` returns expected values of id, tags, context tags + label8lExpectedTags := map[string]string{ + "attributes": "cluster", + "environment": "demo", + "name": "eg-demo-blue-cluster", + "namespace": "eg", + "kubernetes.io/cluster/": "shared", + "upperTEST": "testUPPER", + } + + label8lID := terraform.Output(t, terraformOptions, "label8l_id") + label8lContextID := terraform.Output(t, terraformOptions, "label8l_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8lID) + assert.Equal(t, label8lID, label8lContextID, "ID and context ID should be equal") + + label8lTags := terraform.OutputMap(t, terraformOptions, "label8l_tags") + label8lContextTags := terraform.OutputMap(t, terraformOptions, "label8l_context_tags") + + assert.Exactly(t, label8lExpectedTags, label8lTags, "generated tags are different from expected") + assert.Exactly(t, label8lTags, label8lContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=title` returns expected values of id, tags, context tags + label8tExpectedTags := map[string]string{ + "Attributes": "Eks-Cluster", + "Environment": "Demo", + "Name": "Eg-Demo-Blue-Eks-Cluster", + "Namespace": "Eg", + "kubernetes.io/cluster/": "shared", + } + + label8tID := terraform.Output(t, terraformOptions, "label8t_id") + label8tContextID := terraform.Output(t, terraformOptions, "label8t_context_id") + assert.Equal(t, "Eg-Demo-Blue-Eks-Cluster", label8tID) + assert.Equal(t, label8tID, label8tContextID, "ID and context ID should be equal") + + label8tTags := terraform.OutputMap(t, terraformOptions, "label8t_tags") + label8tContextTags := terraform.OutputMap(t, terraformOptions, "label8t_context_tags") + + assert.Exactly(t, label8tExpectedTags, label8tTags, "generated tags are different from expected") + assert.Exactly(t, label8tTags, label8tContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=upper` and `label_value_case=upper` returns expected values of id, tags, context tags + label8uExpectedTags := map[string]string{ + "ATTRIBUTES": "CLUSTER", + "ENVIRONMENT": "DEMO", + "NAME": "EG-DEMO-BLUE-CLUSTER", + "NAMESPACE": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8uID := terraform.Output(t, terraformOptions, "label8u_id") + label8uContextID := terraform.Output(t, terraformOptions, "label8u_context_id") + assert.Equal(t, "EG-DEMO-BLUE-CLUSTER", label8uID) + assert.Equal(t, label8uID, label8uContextID, "ID and context ID should be equal") + + label8uTags := terraform.OutputMap(t, terraformOptions, "label8u_tags") + label8uContextTags := terraform.OutputMap(t, terraformOptions, "label8u_context_tags") + + assert.Exactly(t, label8uExpectedTags, label8uTags, "generated tags are different from expected") + assert.Exactly(t, label8uTags, label8uContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=none` returns expected values of id, tags, context tags + label8nExpectedTags := map[string]string{ + "Attributes": "eks-ClusteR", + "Environment": "demo", + "Name": "EG-demo-blue-eks-ClusteR", + "Namespace": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8nID := terraform.Output(t, terraformOptions, "label8n_id") + label8nContextID := terraform.Output(t, terraformOptions, "label8n_context_id") + assert.Equal(t, "EG-demo-blue-eks-ClusteR", label8nID) + assert.Equal(t, label8nID, label8nContextID, "ID and context ID should be equal") + + label8nTags := terraform.OutputMap(t, terraformOptions, "label8n_tags") + label8nContextTags := terraform.OutputMap(t, terraformOptions, "label8n_context_tags") + + assert.Exactly(t, label8nExpectedTags, label8nTags, "generated tags are different from expected") + assert.Exactly(t, label8nTags, label8nContextTags, "tags and context tags should be equal") +} diff --git a/.terraform/modules/datadog_integration2.this/test/src/go.mod b/.terraform/modules/datadog_integration2.this/test/src/go.mod new file mode 100755 index 0000000..d866541 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/test/src/go.mod @@ -0,0 +1,9 @@ +module github.com/cloudposse/terraform-null-label + +go 1.14 + +require ( + github.com/gruntwork-io/terratest v0.31.1 + github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 + github.com/stretchr/testify v1.6.1 +) diff --git a/.terraform/modules/datadog_integration2.this/test/src/go.sum b/.terraform/modules/datadog_integration2.this/test/src/go.sum new file mode 100755 index 0000000..b8d46b1 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/test/src/go.sum @@ -0,0 +1,595 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= +github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.5/go.mod h1:foo3aIXRQ90zFve3r0QiDsrjGDUwWhKl0ZOQy1CT14k= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= +github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200109221225-a4f60165b7a3/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= +github.com/gruntwork-io/terratest v0.31.1 h1:MPGe/5pGgJAIZ/hb+0LM1KyJKSi/QyxSkHoP9/CBhJg= +github.com/gruntwork-io/terratest v0.31.1/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= +github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4= +github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= +github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= +k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= +k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= +k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= +k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= +k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= +k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= +k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= +modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/.terraform/modules/datadog_integration2.this/variables.tf b/.terraform/modules/datadog_integration2.this/variables.tf new file mode 100755 index 0000000..40fb268 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/variables.tf @@ -0,0 +1,157 @@ +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} diff --git a/.terraform/modules/datadog_integration2.this/versions.tf b/.terraform/modules/datadog_integration2.this/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/datadog_integration2.this/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/modules.json b/.terraform/modules/modules.json new file mode 100755 index 0000000..af3e41a --- /dev/null +++ b/.terraform/modules/modules.json @@ -0,0 +1 @@ +{"Modules":[{"Key":"datadog_integration2.all_label","Source":"cloudposse/label/null","Version":"0.24.1","Dir":".terraform/modules/datadog_integration2.all_label"},{"Key":"datadog_integration2.lambda_label","Source":"cloudposse/label/null","Version":"0.24.1","Dir":".terraform/modules/datadog_integration2.lambda_label"},{"Key":"datadog_integration.all_label","Source":"cloudposse/label/null","Version":"0.24.1","Dir":".terraform/modules/datadog_integration.all_label"},{"Key":"datadog-monitors-system-generic.filter-tags-disk","Source":"../../common/filter-tags","Dir":".terraform/modules/datadog-monitors-system-generic/common/filter-tags"},{"Key":"datadog_integration.forwarder_rds","Source":"cloudposse/module-artifact/external","Version":"0.7.0","Dir":".terraform/modules/datadog_integration.forwarder_rds"},{"Key":"datadog_integration.this","Source":"cloudposse/label/null","Version":"0.24.1","Dir":".terraform/modules/datadog_integration.this"},{"Key":"datadog_integration2","Source":"cloudposse/datadog-integration/aws","Version":"0.11.0","Dir":".terraform/modules/datadog_integration2"},{"Key":"datadog-integration.core_label","Source":"cloudposse/label/null","Version":"0.24.1","Dir":".terraform/modules/datadog-integration.core_label"},{"Key":"datadog-integration.all_label","Source":"cloudposse/label/null","Version":"0.24.1","Dir":".terraform/modules/datadog-integration.all_label"},{"Key":"datadog-integration","Source":"cloudposse/datadog-integration/aws","Version":"0.11.0","Dir":".terraform/modules/datadog-integration"},{"Key":"","Source":"","Dir":"."},{"Key":"datadog-integration.forwarder_rds_label","Source":"cloudposse/label/null","Version":"0.24.1","Dir":".terraform/modules/datadog-integration.forwarder_rds_label"},{"Key":"datadog_integration2.forwarder_rds.this","Source":"cloudposse/label/null","Version":"0.24.1","Dir":".terraform/modules/datadog_integration2.forwarder_rds.this"},{"Key":"monitors","Source":"claranet/monitors/datadog","Version":"4.0.1","Dir":".terraform/modules/monitors"},{"Key":"datadog-message-alerting-bh-only","Source":"claranet/monitors/datadog//common/alerting-message","Version":"4.0.1","Dir":".terraform/modules/datadog-message-alerting-bh-only/common/alerting-message"},{"Key":"datadog_integration.lambda_label","Source":"cloudposse/label/null","Version":"0.24.1","Dir":".terraform/modules/datadog_integration.lambda_label"},{"Key":"datadog-integration.this","Source":"cloudposse/label/null","Version":"0.24.1","Dir":".terraform/modules/datadog-integration.this"},{"Key":"datadog_integration.forwarder_rds.this","Source":"cloudposse/label/null","Version":"0.24.1","Dir":".terraform/modules/datadog_integration.forwarder_rds.this"},{"Key":"datadog_integration.core_label","Source":"cloudposse/label/null","Version":"0.24.1","Dir":".terraform/modules/datadog_integration.core_label"},{"Key":"datadog_integration","Source":"cloudposse/datadog-integration/aws","Version":"0.11.0","Dir":".terraform/modules/datadog_integration"},{"Key":"datadog-integration.lambda_label","Source":"cloudposse/label/null","Version":"0.24.1","Dir":".terraform/modules/datadog-integration.lambda_label"},{"Key":"datadog-monitors-system-generic.filter-tags","Source":"../../common/filter-tags","Dir":".terraform/modules/datadog-monitors-system-generic/common/filter-tags"},{"Key":"datadog_integration2.forwarder_rds","Source":"cloudposse/module-artifact/external","Version":"0.7.0","Dir":".terraform/modules/datadog_integration2.forwarder_rds"},{"Key":"datadog_integration.forwarder_rds_label","Source":"cloudposse/label/null","Version":"0.24.1","Dir":".terraform/modules/datadog_integration.forwarder_rds_label"},{"Key":"datadog-monitors-system-generic","Source":"claranet/monitors/datadog//system/generic","Version":"4.0.1","Dir":".terraform/modules/datadog-monitors-system-generic/system/generic"},{"Key":"datadog-integration.forwarder_rds","Source":"cloudposse/module-artifact/external","Version":"0.7.0","Dir":".terraform/modules/datadog-integration.forwarder_rds"},{"Key":"datadog-integration.forwarder_rds.this","Source":"cloudposse/label/null","Version":"0.24.1","Dir":".terraform/modules/datadog-integration.forwarder_rds.this"},{"Key":"this","Source":"cloudposse/label/null","Version":"0.24.1","Dir":".terraform/modules/this"},{"Key":"datadog_integration2.this","Source":"cloudposse/label/null","Version":"0.24.1","Dir":".terraform/modules/datadog_integration2.this"},{"Key":"datadog-message-alerting","Source":"claranet/monitors/datadog//common/alerting-message","Version":"4.0.1","Dir":".terraform/modules/datadog-message-alerting/common/alerting-message"},{"Key":"datadog_integration2.core_label","Source":"cloudposse/label/null","Version":"0.24.1","Dir":".terraform/modules/datadog_integration2.core_label"},{"Key":"datadog_integration2.forwarder_rds_label","Source":"cloudposse/label/null","Version":"0.24.1","Dir":".terraform/modules/datadog_integration2.forwarder_rds_label"}]} \ No newline at end of file diff --git a/.terraform/modules/monitors b/.terraform/modules/monitors new file mode 160000 index 0000000..518c7ed --- /dev/null +++ b/.terraform/modules/monitors @@ -0,0 +1 @@ +Subproject commit 518c7ed71b17184fe82bda5b02543def5e37b747 diff --git a/.terraform/modules/this/LICENSE b/.terraform/modules/this/LICENSE new file mode 100755 index 0000000..c844c70 --- /dev/null +++ b/.terraform/modules/this/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017-2020 Cloud Posse, LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/.terraform/modules/this/Makefile b/.terraform/modules/this/Makefile new file mode 100755 index 0000000..97d8087 --- /dev/null +++ b/.terraform/modules/this/Makefile @@ -0,0 +1,10 @@ +SHELL := /bin/bash + +# List of targets the `readme` target should call before generating the readme +export README_DEPS ?= docs/targets.md docs/terraform.md + +-include $(shell curl -sSL -o .build-harness "https://git.io/build-harness"; echo .build-harness) + +## Lint terraform code +lint: + $(SELF) terraform/install terraform/get-modules terraform/get-plugins terraform/lint terraform/validate diff --git a/.terraform/modules/this/README.md b/.terraform/modules/this/README.md new file mode 100755 index 0000000..32950e4 --- /dev/null +++ b/.terraform/modules/this/README.md @@ -0,0 +1,938 @@ + +# terraform-null-label [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-null-label.svg)](https://github.com/cloudposse/terraform-null-label/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) + + +[![README Header][readme_header_img]][readme_header_link] + +[![Cloud Posse][logo]](https://cpco.io/homepage) + + + +Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + +This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. +However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). +So if you prefer the term `stage` to `environment` +you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. +- If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. +- If you want the attributes in a different order, you can specify that, too, with the `label_order` list. +- You can set a maximum length for the name, and the module will create a unique name that fits within that length. +- You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. +- The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + +It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. +For example, if you have 10 instances, there should be 10 different labels. +However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + +All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + +**NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. +With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + +- Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. +- Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. +- Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. + + +--- + +This project is part of our comprehensive ["SweetOps"](https://cpco.io/sweetops) approach towards DevOps. +[][share_email] +[][share_googleplus] +[][share_facebook] +[][share_reddit] +[][share_linkedin] +[][share_twitter] + + +[![Terraform Open Source Modules](https://docs.cloudposse.com/images/terraform-open-source-modules.svg)][terraform_modules] + + + +It's 100% Open Source and licensed under the [APACHE2](LICENSE). + + + + + + + +We literally have [*hundreds of terraform modules*][terraform_modules] that are Open Source and well-maintained. Check them out! + + + + + + + +## Security & Compliance [](https://bridgecrew.io/) + +Security scanning is graciously provided by Bridgecrew. Bridgecrew is the leading fully hosted, cloud-native solution providing continuous Terraform security and compliance. + +| Benchmark | Description | +|--------|---------------| +| [![Infrastructure Security](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/general)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=INFRASTRUCTURE+SECURITY) | Infrastructure Security Compliance | +| [![CIS KUBERNETES](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_kubernetes)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+KUBERNETES+V1.5) | Center for Internet Security, KUBERNETES Compliance | +| [![CIS AWS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_aws)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AWS+V1.2) | Center for Internet Security, AWS Compliance | +| [![CIS AZURE](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_azure)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+AZURE+V1.1) | Center for Internet Security, AZURE Compliance | +| [![PCI-DSS](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/pci)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=PCI-DSS+V3.2) | Payment Card Industry Data Security Standards Compliance | +| [![NIST-800-53](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/nist)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=NIST-800-53) | National Institute of Standards and Technology Compliance | +| [![ISO27001](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/iso)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=ISO27001) | Information Security Management System, ISO/IEC 27001 Compliance | +| [![SOC2](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/soc2)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=SOC2)| Service Organization Control 2 Compliance | +| [![CIS GCP](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/cis_gcp)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=CIS+GCP+V1.1) | Center for Internet Security, GCP Compliance | +| [![HIPAA](https://www.bridgecrew.cloud/badges/github/cloudposse/terraform-null-label/hipaa)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=cloudposse%2Fterraform-null-label&benchmark=HIPAA) | Health Insurance Portability and Accountability Compliance | + + + +## Usage + + +**IMPORTANT:** We do not pin modules to versions in our examples because of the +difficulty of keeping the versions in the documentation in sync with the latest released versions. +We highly recommend that in your code you pin the version to the exact version you are +using so that your infrastructure remains stable, and update versions in a +systematic way so that they do not catch you by surprise. + +Also, because of a bug in the Terraform registry ([hashicorp/terraform#21417](https://github.com/hashicorp/terraform/issues/21417)), +the registry shows many of our inputs as required when in fact they are optional. +The table below correctly indicates which inputs are required. + + +### Defaults + +Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. +The context object is a single object that contains all the input values for `terraform-null-label`. +However, each input value can also be specified individually by name as a standard Terraform variable, +and the value of those variables, when set to something other than `null`, will override the value +in the context object. In order to allow chaining of these objects, where the context object input to one +module is transformed and passed to the next module, all the variables default to `null` or empty collections. +The actual default values used when nothing is explicitly set are describe in the documentation below. + +For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, +`terraform-null-label` will actually use the default delimiter `-` (hyphen). + +A non-obvious but intentional consequence of this design is that once a module sets a non-default value, +future modules in the chain cannot reset the value back to the original default. Insted, the new setting +becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, +so once a tag is added, it will remain in the tag set and cannot be removed, although its value can +be overwritten. + +### Simple Example + +```hcl +module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} +``` + +This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` +(you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + +Now reference the label when creating an instance: + +```hcl +resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags +} +``` + +Or define a security group: + +```hcl +resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} +``` + + +### Advanced Example + +Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + +```hcl +module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] +} + +module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } +} + +resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] +} +``` + +
+ +### Advanced Example 2 + +Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + +```hcl +tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } +] +``` + +Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + +```hcl +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} +``` + +
+ +### Advanced Example 3 + +See [complete example](./examples/complete) for even more examples. + +This example shows how you can pass the `context` output of one label module to the next label_module, +allowing you to create one label that has the base set of values, and then creating every extra label +as a derivative of that. + +
Click to show + +```hcl +module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} +``` + +This creates label outputs like this: + +```hcl +label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" +} +label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } +} +label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } +} +label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" +} +label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" +} +label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } +} +label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" +} +label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, +] +label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" +} +label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } +} +label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } +} +label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" +} + +``` + +
+ + + + + + + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + + + + +## Share the Love + +Like this project? Please give it a ★ on [our GitHub](https://github.com/cloudposse/terraform-null-label)! (it helps us **a lot**) + +Are you using this project or any of our other projects? Consider [leaving a testimonial][testimonial]. =) + + +## Related Projects + +Check out these related projects. + +- [terraform-terraform-label](https://github.com/cloudposse/terraform-terraform-label) - Terraform Module to define a consistent naming convention by (namespace, environment, stage, name, [attributes]) + + + +## Help + +**Got a question?** We got answers. + +File a GitHub [issue](https://github.com/cloudposse/terraform-null-label/issues), send us an [email][email] or join our [Slack Community][slack]. + +[![README Commercial Support][readme_commercial_support_img]][readme_commercial_support_link] + +## DevOps Accelerator for Startups + + +We are a [**DevOps Accelerator**][commercial_support]. We'll help you build your cloud infrastructure from the ground up so you can own it. Then we'll show you how to operate it and stick around for as long as you need us. + +[![Learn More](https://img.shields.io/badge/learn%20more-success.svg?style=for-the-badge)][commercial_support] + +Work directly with our team of DevOps experts via email, slack, and video conferencing. + +We deliver 10x the value for a fraction of the cost of a full-time engineer. Our track record is not even funny. If you want things done right and you need it done FAST, then we're your best bet. + +- **Reference Architecture.** You'll get everything you need from the ground up built using 100% infrastructure as code. +- **Release Engineering.** You'll have end-to-end CI/CD with unlimited staging environments. +- **Site Reliability Engineering.** You'll have total visibility into your apps and microservices. +- **Security Baseline.** You'll have built-in governance with accountability and audit logs for all changes. +- **GitOps.** You'll be able to operate your infrastructure via Pull Requests. +- **Training.** You'll receive hands-on training so your team can operate what we build. +- **Questions.** You'll have a direct line of communication between our teams via a Shared Slack channel. +- **Troubleshooting.** You'll get help to triage when things aren't working. +- **Code Reviews.** You'll receive constructive feedback on Pull Requests. +- **Bug Fixes.** We'll rapidly work with you to fix any bugs in our projects. + +## Slack Community + +Join our [Open Source Community][slack] on Slack. It's **FREE** for everyone! Our "SweetOps" community is where you get to talk with others who share a similar vision for how to rollout and manage infrastructure. This is the best place to talk shop, ask questions, solicit feedback, and work together as a community to build totally *sweet* infrastructure. + +## Discourse Forums + +Participate in our [Discourse Forums][discourse]. Here you'll find answers to commonly asked questions. Most questions will be related to the enormous number of projects we support on our GitHub. Come here to collaborate on answers, find solutions, and get ideas about the products and services we value. It only takes a minute to get started! Just sign in with SSO using your GitHub account. + +## Newsletter + +Sign up for [our newsletter][newsletter] that covers everything on our technology radar. Receive updates on what we're up to on GitHub as well as awesome new projects we discover. + +## Office Hours + +[Join us every Wednesday via Zoom][office_hours] for our weekly "Lunch & Learn" sessions. It's **FREE** for everyone! + +[![zoom](https://img.cloudposse.com/fit-in/200x200/https://cloudposse.com/wp-content/uploads/2019/08/Powered-by-Zoom.png")][office_hours] + +## Contributing + +### Bug Reports & Feature Requests + +Please use the [issue tracker](https://github.com/cloudposse/terraform-null-label/issues) to report any bugs or file feature requests. + +### Developing + +If you are interested in being a contributor and want to get involved in developing this project or [help out](https://cpco.io/help-out) with our other projects, we would love to hear from you! Shoot us an [email][email]. + +In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. + + 1. **Fork** the repo on GitHub + 2. **Clone** the project to your own machine + 3. **Commit** changes to your own branch + 4. **Push** your work back up to your fork + 5. Submit a **Pull Request** so that we can review your changes + +**NOTE:** Be sure to merge the latest changes from "upstream" before making a pull request! + + +## Copyright + +Copyright © 2017-2021 [Cloud Posse, LLC](https://cpco.io/copyright) + + + +## License + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +See [LICENSE](LICENSE) for full details. + +```text +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +``` + + + + + + + + + +## Trademarks + +All other trademarks referenced herein are the property of their respective owners. + +## About + +This project is maintained and funded by [Cloud Posse, LLC][website]. Like it? Please let us know by [leaving a testimonial][testimonial]! + +[![Cloud Posse][logo]][website] + +We're a [DevOps Professional Services][hire] company based in Los Angeles, CA. We ❤️ [Open Source Software][we_love_open_source]. + +We offer [paid support][commercial_support] on all of our projects. + +Check out [our other projects][github], [follow us on twitter][twitter], [apply for a job][jobs], or [hire us][hire] to help with your cloud strategy and implementation. + + + +### Contributors + + +| [![Erik Osterman][osterman_avatar]][osterman_homepage]
[Erik Osterman][osterman_homepage] | [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]
[Andriy Knysh][aknysh_homepage] | [![Igor Rodionov][goruha_avatar]][goruha_homepage]
[Igor Rodionov][goruha_homepage] | [![Sergey Vasilyev][s2504s_avatar]][s2504s_homepage]
[Sergey Vasilyev][s2504s_homepage] | [![Michael Pereira][MichaelPereira_avatar]][MichaelPereira_homepage]
[Michael Pereira][MichaelPereira_homepage] | [![Jamie Nelson][Jamie-BitFlight_avatar]][Jamie-BitFlight_homepage]
[Jamie Nelson][Jamie-BitFlight_homepage] | [![Vladimir][SweetOps_avatar]][SweetOps_homepage]
[Vladimir][SweetOps_homepage] | [![Daren Desjardins][darend_avatar]][darend_homepage]
[Daren Desjardins][darend_homepage] | [![Maarten van der Hoef][maartenvanderhoef_avatar]][maartenvanderhoef_homepage]
[Maarten van der Hoef][maartenvanderhoef_homepage] | [![Adam Tibbing][tibbing_avatar]][tibbing_homepage]
[Adam Tibbing][tibbing_homepage] | +|---|---|---|---|---|---|---|---|---|---| + + + [osterman_homepage]: https://github.com/osterman + [osterman_avatar]: https://img.cloudposse.com/150x150/https://github.com/osterman.png + [aknysh_homepage]: https://github.com/aknysh + [aknysh_avatar]: https://img.cloudposse.com/150x150/https://github.com/aknysh.png + [goruha_homepage]: https://github.com/goruha + [goruha_avatar]: https://img.cloudposse.com/150x150/https://github.com/goruha.png + [s2504s_homepage]: https://github.com/s2504s + [s2504s_avatar]: https://img.cloudposse.com/150x150/https://github.com/s2504s.png + [MichaelPereira_homepage]: https://github.com/MichaelPereira + [MichaelPereira_avatar]: https://img.cloudposse.com/150x150/https://github.com/MichaelPereira.png + [Jamie-BitFlight_homepage]: https://github.com/Jamie-BitFlight + [Jamie-BitFlight_avatar]: https://img.cloudposse.com/150x150/https://github.com/Jamie-BitFlight.png + [SweetOps_homepage]: https://github.com/SweetOps + [SweetOps_avatar]: https://img.cloudposse.com/150x150/https://github.com/SweetOps.png + [darend_homepage]: https://github.com/darend + [darend_avatar]: https://img.cloudposse.com/150x150/https://github.com/darend.png + [maartenvanderhoef_homepage]: https://github.com/maartenvanderhoef + [maartenvanderhoef_avatar]: https://img.cloudposse.com/150x150/https://github.com/maartenvanderhoef.png + [tibbing_homepage]: https://github.com/tibbing + [tibbing_avatar]: https://img.cloudposse.com/150x150/https://github.com/tibbing.png + +[![README Footer][readme_footer_img]][readme_footer_link] +[![Beacon][beacon]][website] + + [logo]: https://cloudposse.com/logo-300x69.svg + [docs]: https://cpco.io/docs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=docs + [website]: https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=website + [github]: https://cpco.io/github?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=github + [jobs]: https://cpco.io/jobs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=jobs + [hire]: https://cpco.io/hire?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=hire + [slack]: https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=slack + [linkedin]: https://cpco.io/linkedin?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=linkedin + [twitter]: https://cpco.io/twitter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=twitter + [testimonial]: https://cpco.io/leave-testimonial?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=testimonial + [office_hours]: https://cloudposse.com/office-hours?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=office_hours + [newsletter]: https://cpco.io/newsletter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=newsletter + [discourse]: https://ask.sweetops.com/?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=discourse + [email]: https://cpco.io/email?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=email + [commercial_support]: https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=commercial_support + [we_love_open_source]: https://cpco.io/we-love-open-source?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=we_love_open_source + [terraform_modules]: https://cpco.io/terraform-modules?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=terraform_modules + [readme_header_img]: https://cloudposse.com/readme/header/img + [readme_header_link]: https://cloudposse.com/readme/header/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_header_link + [readme_footer_img]: https://cloudposse.com/readme/footer/img + [readme_footer_link]: https://cloudposse.com/readme/footer/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_footer_link + [readme_commercial_support_img]: https://cloudposse.com/readme/commercial-support/img + [readme_commercial_support_link]: https://cloudposse.com/readme/commercial-support/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-null-label&utm_content=readme_commercial_support_link + [share_twitter]: https://twitter.com/intent/tweet/?text=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_linkedin]: https://www.linkedin.com/shareArticle?mini=true&title=terraform-null-label&url=https://github.com/cloudposse/terraform-null-label + [share_reddit]: https://reddit.com/submit/?url=https://github.com/cloudposse/terraform-null-label + [share_facebook]: https://facebook.com/sharer/sharer.php?u=https://github.com/cloudposse/terraform-null-label + [share_googleplus]: https://plus.google.com/share?url=https://github.com/cloudposse/terraform-null-label + [share_email]: mailto:?subject=terraform-null-label&body=https://github.com/cloudposse/terraform-null-label + [beacon]: https://ga-beacon.cloudposse.com/UA-76589703-4/cloudposse/terraform-null-label?pixel&cs=github&cm=readme&an=terraform-null-label diff --git a/.terraform/modules/this/README.yaml b/.terraform/modules/this/README.yaml new file mode 100755 index 0000000..42bdb84 --- /dev/null +++ b/.terraform/modules/this/README.yaml @@ -0,0 +1,618 @@ +name: terraform-null-label +tags: +- aws +- terraform +- terraform-modules +- naming-convention +- name +- namespace +- stage +categories: +- terraform-modules/supported +license: APACHE2 +github_repo: cloudposse/terraform-null-label +badges: +- name: Latest Release + image: https://img.shields.io/github/release/cloudposse/terraform-null-label.svg + url: https://github.com/cloudposse/terraform-null-label/releases/latest +- name: Slack Community + image: https://slack.cloudposse.com/badge.svg + url: https://slack.cloudposse.com +related: +- name: terraform-terraform-label + description: Terraform Module to define a consistent naming convention by (namespace, + environment, stage, name, [attributes]) + url: https://github.com/cloudposse/terraform-terraform-label +description: |- + Terraform module designed to generate consistent names and tags for resources. Use `terraform-null-label` to implement a strict naming convention. + + This module generates names using the following convention by default: `{namespace}-{environment}-{stage}-{name}-{attributes}`. + However, it is highly configurable. The delimiter (e.g. `-`) is configurable. Each label item is optional (although you must provide at least one). + So if you prefer the term `stage` to `environment` + you can exclude environment and the label `id` will look like `{namespace}-{stage}-{name}-{attributes}`. + - If attributes are excluded but `namespace`, `stage`, and `environment` are included, `id` will look like `{namespace}-{environment}-{stage}-{name}`. + - If you want the attributes in a different order, you can specify that, too, with the `label_order` list. + - You can set a maximum length for the name, and the module will create a unique name that fits within that length. + - You can control the letter case of the generated labels which make up the `id` using `var.label_value_case`. + - The labels are also exported as tags. You can control the case of the tag names (keys) using `var.label_tag_case`. + + It's recommended to use one `terraform-null-label` module for every unique resource of a given resource type. + For example, if you have 10 instances, there should be 10 different labels. + However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + + All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. + + **NOTE:** The `null` originally referred to the primary Terraform [provider](https://www.terraform.io/docs/providers/null/index.html) used in this module. + With Terraform 0.12, this module no longer needs any provider, but the name was kept for continuity. + + - Releases of this module from `0.23.0` onward only work with Terraform 0.13 or newer. + - Releases of this module from `0.12.0` through `0.22.1` support `HCL2` and are compatible with Terraform 0.12 or newer. + - Releases of this module prior to `0.12.0` are compatible with earlier versions of terraform like Terraform 0.11. +usage: |- + ### Defaults + + Cloud Posse Terraform modules share a common `context` object that is meant to be passed from module to module. + The context object is a single object that contains all the input values for `terraform-null-label`. + However, each input value can also be specified individually by name as a standard Terraform variable, + and the value of those variables, when set to something other than `null`, will override the value + in the context object. In order to allow chaining of these objects, where the context object input to one + module is transformed and passed to the next module, all the variables default to `null` or empty collections. + The actual default values used when nothing is explicitly set are describe in the documentation below. + + For example, the default value of `delimiter` is shown as `null`, but if you leave it set to null, + `terraform-null-label` will actually use the default delimiter `-` (hyphen). + + A non-obvious but intentional consequence of this design is that once a module sets a non-default value, + future modules in the chain cannot reset the value back to the original default. Insted, the new setting + becomes the new default for downstream modules. Also, collections are not overwritten, they are merged, + so once a tag is added, it will remain in the tag set and cannot be removed, although its value can + be overwritten. + + ### Simple Example + + ```hcl + module "eg_prod_bastion_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["public"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + ``` + + This will create an `id` with the value of `eg-prod-bastion-public` because when generating `id`, the default order is `namespace`, `environment`, `stage`, `name`, `attributes` + (you can override it by using the `label_order` variable, see [Advanced Example 3](#advanced-example-3)). + + Now reference the label when creating an instance: + + ```hcl + resource "aws_instance" "eg_prod_bastion_public" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_label.tags + } + ``` + + Or define a security group: + + ```hcl + resource "aws_security_group" "eg_prod_bastion_public" { + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + } + ``` + + + ### Advanced Example + + Here is a more complex example with two instances using two different labels. Note how efficiently the tags are defined for both the instance and the security group. + +
Click to show + + ```hcl + module "eg_prod_bastion_abc_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["abc"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_abc" { + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_abc" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_abc_label.tags +   vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] + } + + module "eg_prod_bastion_xyz_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "eg" + stage = "prod" + name = "bastion" + attributes = ["xyz"] + delimiter = "-" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } + } + + resource "aws_security_group" "eg_prod_bastion_xyz" { + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + resource "aws_instance" "eg_prod_bastion_xyz" { + instance_type = "t1.micro" + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] + } + ``` + +
+ + ### Advanced Example 2 + + Here is a more complex example with an autoscaling group that has a different tagging schema than other resources and requires its tags to be in this format, which this module can generate: + +
Click to show + + ```hcl + tags = [ + { + key = Name, + propagate_at_launch = 1, + value = namespace-stage-name + }, + { + key = Namespace, + propagate_at_launch = 1, + value = namespace + }, + { + key = Stage, + propagate_at_launch = 1, + value = stage + } + ] + ``` + + Autoscaling group using propagating tagging below (full example: [autoscalinggroup](examples/autoscalinggroup/main.tf)) + + ```hcl + ################################ + # terraform-null-label example # + ################################ + module "label" { + source = "../../" + namespace = "cp" + stage = "prod" + name = "app" + + tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" + } + + additional_tag_map = { + propagate_at_launch = "true" + } + } + + ####################### + # Launch template # + ####################### + resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } + } + + ###################### + # Autoscaling group # + ###################### + resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template = { + id = "aws_launch_template.default.id + version = "$$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps + } + ``` + +
+ + ### Advanced Example 3 + + See [complete example](./examples/complete) for even more examples. + + This example shows how you can pass the `context` output of one label module to the next label_module, + allowing you to create one label that has the base set of values, and then creating every extra label + as a derivative of that. + +
Click to show + + ```hcl + module "label1" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } + } + + module "label2" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + + tags = { + "City" = "London" + "Environment" = "Public" + } + } + + module "label3" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } + } + ``` + + This creates label outputs like this: + + ```hcl + label1 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "id" = "winstonchurchroom-uat-build-fire-water-earth-air" + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "stage" = "build" + } + label1_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Winston Churchroom" + "namespace" = "CloudPosse" + "stage" = "build" + "tags" = { + "City" = "Dublin" + "Environment" = "Private" + } + } + label1_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "-" + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "winstonchurchroom" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9]/" + "stage" = "build" + "tags" = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + } + label1_tags = { + "Attributes" = "fire-water-earth-air" + "City" = "Dublin" + "Environment" = "Private" + "Name" = "winstonchurchroom-uat-build-fire-water-earth-air" + "Namespace" = "cloudposse" + "Stage" = "build" + } + label2 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "id" = "charlie+uat+test+fire+water+earth+air" + "name" = "charlie" + "namespace" = "cloudposse" + "stage" = "test" + } + label2_context = { + "additional_tag_map" = { + "additional_tag" = "yes" + "propagate_at_launch" = "true" + } + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "+" + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Charlie" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^a-zA-Z0-9-+]/" + "stage" = "test" + "tags" = { + "City" = "London" + "Environment" = "Public" + } + } + label2_tags = { + "Attributes" = "fire+water+earth+air" + "City" = "London" + "Environment" = "Public" + "Name" = "charlie+uat+test+fire+water+earth+air" + "Namespace" = "cloudposse" + "Stage" = "test" + } + label2_tags_as_list_of_maps = [ + { + "additional_tag" = "yes" + "key" = "Attributes" + "propagate_at_launch" = "true" + "value" = "fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "City" + "propagate_at_launch" = "true" + "value" = "London" + }, + { + "additional_tag" = "yes" + "key" = "Environment" + "propagate_at_launch" = "true" + "value" = "Public" + }, + { + "additional_tag" = "yes" + "key" = "Name" + "propagate_at_launch" = "true" + "value" = "charlie+uat+test+fire+water+earth+air" + }, + { + "additional_tag" = "yes" + "key" = "Namespace" + "propagate_at_launch" = "true" + "value" = "cloudposse" + }, + { + "additional_tag" = "yes" + "key" = "Stage" + "propagate_at_launch" = "true" + "value" = "test" + }, + ] + label3 = { + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "id" = "starfish.uat.release.fire.water.earth.air" + "name" = "starfish" + "namespace" = "cloudposse" + "stage" = "release" + } + label3_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "UAT" + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "Starfish" + "namespace" = "CloudPosse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + } + } + label3_normalized_context = { + "additional_tag_map" = {} + "attributes" = [ + "fire", + "water", + "earth", + "air", + ] + "delimiter" = "." + "enabled" = true + "environment" = "uat" + "id_length_limit" = 0 + "label_order" = [ + "name", + "environment", + "stage", + "attributes", + ] + "name" = "starfish" + "namespace" = "cloudposse" + "regex_replace_chars" = "/[^-a-zA-Z0-9.]/" + "stage" = "release" + "tags" = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + } + label3_tags = { + "Animal" = "Rabbit" + "Attributes" = "fire.water.earth.air" + "City" = "Dublin" + "Eat" = "Carrot" + "Environment" = "Private" + "Name" = "starfish.uat.release.fire.water.earth.air" + "Namespace" = "cloudposse" + "Stage" = "release" + } + + ``` + +
+ +include: +- docs/targets.md +- docs/terraform.md +contributors: +- name: Erik Osterman + github: osterman +- name: Andriy Knysh + github: aknysh +- name: Igor Rodionov + github: goruha +- name: Sergey Vasilyev + github: s2504s +- name: Michael Pereira + github: MichaelPereira +- name: Jamie Nelson + github: Jamie-BitFlight +- name: Vladimir + github: SweetOps +- name: Daren Desjardins + github: darend +- name: Maarten van der Hoef + github: maartenvanderhoef +- name: Adam Tibbing + github: tibbing diff --git a/.terraform/modules/this/docs/targets.md b/.terraform/modules/this/docs/targets.md new file mode 100755 index 0000000..3dce8b3 --- /dev/null +++ b/.terraform/modules/this/docs/targets.md @@ -0,0 +1,12 @@ + +## Makefile Targets +```text +Available targets: + + help Help screen + help/all Display help for all targets + help/short This help short screen + lint Lint terraform code + +``` + diff --git a/.terraform/modules/this/docs/terraform.md b/.terraform/modules/this/docs/terraform.md new file mode 100755 index 0000000..d4f48f4 --- /dev/null +++ b/.terraform/modules/this/docs/terraform.md @@ -0,0 +1,54 @@ + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.13.0 | + +## Providers + +No provider. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | +| attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_key\_case | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| label\_value\_case | The letter case of output label values (also used in `tags` and `id`).
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Default value: `lower`. | `string` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| additional\_tag\_map | The merged additional\_tag\_map | +| attributes | List of attributes | +| context | Merged but otherwise unmodified input to this module, to be used as context input to other modules.
Note: this version will have null values as defaults, not the values actually used as defaults. | +| delimiter | Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes` | +| enabled | True if module is enabled, false otherwise | +| environment | Normalized environment | +| id | Disambiguated ID restricted to `id_length_limit` characters in total | +| id\_full | Disambiguated ID not restricted in length | +| id\_length\_limit | The id\_length\_limit actually used to create the ID, with `0` meaning unlimited | +| label\_order | The naming order actually used to create the ID | +| name | Normalized name | +| namespace | Normalized namespace | +| normalized\_context | Normalized context of this module | +| regex\_replace\_chars | The regex\_replace\_chars actually used to create the ID | +| stage | Normalized stage | +| tags | Normalized Tag map | +| tags\_as\_list\_of\_maps | Additional tags as a list of maps, which can be used in several AWS resources | + + diff --git a/.terraform/modules/this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars b/.terraform/modules/this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars new file mode 100755 index 0000000..f7c725f --- /dev/null +++ b/.terraform/modules/this/examples/autoscalinggroup/autoscalinggroup.auto.tfvars @@ -0,0 +1,12 @@ +namespace = "eg" +stage = "prod" +name = "app" + +tags = { + BusinessUnit = "Finance" + ManagedBy = "Terraform" +} + +additional_tag_map = { + propagate_at_launch = "true" +} diff --git a/.terraform/modules/this/examples/autoscalinggroup/context.tf b/.terraform/modules/this/examples/autoscalinggroup/context.tf new file mode 100755 index 0000000..b97f05f --- /dev/null +++ b/.terraform/modules/this/examples/autoscalinggroup/context.tf @@ -0,0 +1,216 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/this/examples/autoscalinggroup/main.tf b/.terraform/modules/this/examples/autoscalinggroup/main.tf new file mode 100755 index 0000000..f0d3aa6 --- /dev/null +++ b/.terraform/modules/this/examples/autoscalinggroup/main.tf @@ -0,0 +1,104 @@ +################################ +# terraform-null-label example # +################################ +module "label" { + source = "../../" + + context = module.this.context +} + +####################### +# Launch template # +####################### +resource "aws_launch_template" "default" { + # terraform-null-label example used here: Set template name prefix + name_prefix = "${module.label.id}-" + image_id = data.aws_ami.amazon_linux.id + instance_type = "t2.micro" + instance_initiated_shutdown_behavior = "terminate" + + vpc_security_group_ids = [data.aws_security_group.default.id] + + monitoring { + enabled = false + } + + # terraform-null-label example used here: Set tags on volumes + tag_specifications { + resource_type = "volume" + tags = module.label.tags + } +} + +###################### +# Autoscaling group # +###################### +resource "aws_autoscaling_group" "default" { + # terraform-null-label example used here: Set ASG name prefix + name_prefix = "${module.label.id}-" + vpc_zone_identifier = data.aws_subnet_ids.all.ids + max_size = "1" + min_size = "1" + desired_capacity = "1" + + launch_template { + id = aws_launch_template.default.id + version = "$Latest" + } + + # terraform-null-label example used here: Set tags on ASG and EC2 Servers + tags = module.label.tags_as_list_of_maps +} + +################################ +# Provider # +################################ +provider "aws" { + region = "eu-west-1" + + # Make it faster by skipping unneeded checks here + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +############################################################## +# Data sources to get VPC, subnets and security group details +############################################################## +data "aws_vpc" "default" { + default = true +} + +data "aws_subnet_ids" "all" { + vpc_id = data.aws_vpc.default.id +} + +data "aws_security_group" "default" { + vpc_id = data.aws_vpc.default.id + name = "default" +} + +data "aws_ami" "amazon_linux" { + most_recent = true + + owners = ["amazon"] + + filter { + name = "name" + + values = [ + "amzn-ami-hvm-*-x86_64-gp2", + ] + } + + filter { + name = "owner-alias" + + values = [ + "amazon", + ] + } +} + diff --git a/.terraform/modules/this/examples/autoscalinggroup/outputs.tf b/.terraform/modules/this/examples/autoscalinggroup/outputs.tf new file mode 100755 index 0000000..f8fcce5 --- /dev/null +++ b/.terraform/modules/this/examples/autoscalinggroup/outputs.tf @@ -0,0 +1,12 @@ +# terraform-null-label example used here: Output list of tags applied in each format +output "tags_as_list_of_maps" { + value = module.label.tags_as_list_of_maps +} + +output "tags" { + value = module.label.tags +} + +output "id" { + value = module.label.id +} diff --git a/.terraform/modules/this/examples/autoscalinggroup/versions.tf b/.terraform/modules/this/examples/autoscalinggroup/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/this/examples/autoscalinggroup/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/this/examples/complete/complete.auto.tfvars b/.terraform/modules/this/examples/complete/complete.auto.tfvars new file mode 100755 index 0000000..e7bc519 --- /dev/null +++ b/.terraform/modules/this/examples/complete/complete.auto.tfvars @@ -0,0 +1,10 @@ +namespace = "cp" +environment = "uw2" +stage = "prd" +name = "null-label" + +delimiter = "" +id_length_limit = 6 + +label_key_case = "lower" +label_value_case = "upper" diff --git a/.terraform/modules/this/examples/complete/context.tf b/.terraform/modules/this/examples/complete/context.tf new file mode 100755 index 0000000..973d4dc --- /dev/null +++ b/.terraform/modules/this/examples/complete/context.tf @@ -0,0 +1,217 @@ +# DO NOT COPY THIS FILE +# +# This is a specially modified version of this file, since it is used to test +# the unpublished version of this module. Normally you should use a +# copy of the file as explained below. +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../.." + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + label_key_case = string + label_value_case = string + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = var.context["label_key_case"] == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = var.context["label_value_case"] == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/this/examples/complete/label1.tf b/.terraform/modules/this/examples/complete/label1.tf new file mode 100755 index 0000000..8da353b --- /dev/null +++ b/.terraform/modules/this/examples/complete/label1.tf @@ -0,0 +1,42 @@ +module "label1" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + stage = "build" + name = "Winston Churchroom" + attributes = ["fire", "water", "earth", "air"] + delimiter = "-" + + label_order = ["name", "environment", "stage", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label1" { + value = { + id = module.label1.id + name = module.label1.name + namespace = module.label1.namespace + stage = module.label1.stage + attributes = module.label1.attributes + delimiter = module.label1.delimiter + } +} + +output "label1_tags" { + value = module.label1.tags +} + +output "label1_context" { + value = module.label1.context +} + +output "label1_normalized_context" { + value = module.label1.normalized_context +} + + + diff --git a/.terraform/modules/this/examples/complete/label1t1.tf b/.terraform/modules/this/examples/complete/label1t1.tf new file mode 100755 index 0000000..2bcb362 --- /dev/null +++ b/.terraform/modules/this/examples/complete/label1t1.tf @@ -0,0 +1,18 @@ +module "label1t1" { + source = "../../" + + id_length_limit = 28 + + context = module.label1.context +} + +output "label1t1" { + value = { + id = module.label1t1.id + id_full = module.label1t1.id_full + } +} + +output "label1t1_tags" { + value = module.label1t1.tags +} \ No newline at end of file diff --git a/.terraform/modules/this/examples/complete/label1t2.tf b/.terraform/modules/this/examples/complete/label1t2.tf new file mode 100755 index 0000000..5df651e --- /dev/null +++ b/.terraform/modules/this/examples/complete/label1t2.tf @@ -0,0 +1,18 @@ +module "label1t2" { + source = "../../" + + id_length_limit = 29 + + context = module.label1.context +} + +output "label1t2" { + value = { + id = module.label1t2.id + id_full = module.label1t2.id_full + } +} + +output "label1t2_tags" { + value = module.label1t2.tags +} \ No newline at end of file diff --git a/.terraform/modules/this/examples/complete/label2.tf b/.terraform/modules/this/examples/complete/label2.tf new file mode 100755 index 0000000..faf7450 --- /dev/null +++ b/.terraform/modules/this/examples/complete/label2.tf @@ -0,0 +1,42 @@ +module "label2" { + source = "../../" + context = module.label1.context + name = "Charlie" + stage = "test" + delimiter = "+" + regex_replace_chars = "/[^a-zA-Z0-9-+]/" + + additional_tag_map = { + propagate_at_launch = "true" + additional_tag = "yes" + } + + + tags = { + "City" = "London" + "Environment" = "Public" + } +} + +output "label2" { + value = { + id = module.label2.id + name = module.label2.name + namespace = module.label2.namespace + stage = module.label2.stage + attributes = module.label2.attributes + delimiter = module.label2.delimiter + } +} + +output "label2_tags" { + value = module.label2.tags +} + +output "label2_tags_as_list_of_maps" { + value = module.label2.tags_as_list_of_maps +} + +output "label2_context" { + value = module.label2.context +} diff --git a/.terraform/modules/this/examples/complete/label3c.tf b/.terraform/modules/this/examples/complete/label3c.tf new file mode 100755 index 0000000..338a636 --- /dev/null +++ b/.terraform/modules/this/examples/complete/label3c.tf @@ -0,0 +1,36 @@ +module "label3c" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3c" { + value = { + id = module.label3c.id + name = module.label3c.name + namespace = module.label3c.namespace + stage = module.label3c.stage + attributes = module.label3c.attributes + delimiter = module.label3c.delimiter + } +} + +output "label3c_tags" { + value = module.label3c.tags +} + +output "label3c_context" { + value = module.label3c.context +} + +output "label3c_normalized_context" { + value = module.label3c.normalized_context +} diff --git a/.terraform/modules/this/examples/complete/label3n.tf b/.terraform/modules/this/examples/complete/label3n.tf new file mode 100755 index 0000000..ca51282 --- /dev/null +++ b/.terraform/modules/this/examples/complete/label3n.tf @@ -0,0 +1,36 @@ +module "label3n" { + source = "../../" + name = "Starfish" + stage = "release" + context = module.label1.normalized_context + delimiter = "." + regex_replace_chars = "/[^-a-zA-Z0-9.]/" + + tags = { + "Eat" = "Carrot" + "Animal" = "Rabbit" + } +} + +output "label3n" { + value = { + id = module.label3n.id + name = module.label3n.name + namespace = module.label3n.namespace + stage = module.label3n.stage + attributes = module.label3n.attributes + delimiter = module.label3n.delimiter + } +} + +output "label3n_tags" { + value = module.label3n.tags +} + +output "label3n_context" { + value = module.label3n.context +} + +output "label3n_normalized_context" { + value = module.label3n.normalized_context +} diff --git a/.terraform/modules/this/examples/complete/label4.tf b/.terraform/modules/this/examples/complete/label4.tf new file mode 100755 index 0000000..74e3ca1 --- /dev/null +++ b/.terraform/modules/this/examples/complete/label4.tf @@ -0,0 +1,34 @@ +module "label4" { + source = "../../" + namespace = "CloudPosse" + environment = "UAT" + name = "Example Cluster" + attributes = ["big", "fat", "honking", "cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + "City" = "Dublin" + "Environment" = "Private" + } +} + +output "label4" { + value = { + id = module.label4.id + name = module.label4.name + namespace = module.label4.namespace + stage = module.label4.stage + attributes = module.label4.attributes + delimiter = module.label4.delimiter + } +} + +output "label4_tags" { + value = module.label4.tags +} + +output "label4_context" { + value = module.label4.context +} diff --git a/.terraform/modules/this/examples/complete/label5.tf b/.terraform/modules/this/examples/complete/label5.tf new file mode 100755 index 0000000..0f0a76e --- /dev/null +++ b/.terraform/modules/this/examples/complete/label5.tf @@ -0,0 +1,33 @@ +module "label5" { + source = "../../" + enabled = false + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + label_order = ["namespace", "stage", "environment", "attributes"] + + tags = { + } +} + +output "label5" { + value = { + id = module.label5.id + name = module.label5.name + namespace = module.label5.namespace + stage = module.label5.stage + attributes = module.label5.attributes + delimiter = module.label5.delimiter + } +} + +output "label5_tags" { + value = module.label5.tags +} + +output "label5_context" { + value = module.label5.context +} diff --git a/.terraform/modules/this/examples/complete/label6f.tf b/.terraform/modules/this/examples/complete/label6f.tf new file mode 100755 index 0000000..1ce1bab --- /dev/null +++ b/.terraform/modules/this/examples/complete/label6f.tf @@ -0,0 +1,20 @@ +module "label6f" { + source = "../../" + + delimiter = "~" + id_length_limit = 0 + + # Use values from tfvars + context = module.this.context +} + +output "label6f" { + value = { + id = module.label6f.id + id_full = module.label6f.id_full + } +} + +output "label6f_tags" { + value = module.label6f.tags +} \ No newline at end of file diff --git a/.terraform/modules/this/examples/complete/label6t.tf b/.terraform/modules/this/examples/complete/label6t.tf new file mode 100755 index 0000000..b5d9bc1 --- /dev/null +++ b/.terraform/modules/this/examples/complete/label6t.tf @@ -0,0 +1,19 @@ +module "label6t" { + source = "../../" + + # Use values from tfvars, + # specifically: complete.auto.tfvars + context = module.this.context +} + +output "label6t" { + value = { + id = module.label6t.id + id_full = module.label6t.id_full + id_length_limit = module.this.context.id_length_limit + } +} + +output "label6t_tags" { + value = module.label6t.tags +} \ No newline at end of file diff --git a/.terraform/modules/this/examples/complete/label7.tf b/.terraform/modules/this/examples/complete/label7.tf new file mode 100755 index 0000000..bb365d4 --- /dev/null +++ b/.terraform/modules/this/examples/complete/label7.tf @@ -0,0 +1,44 @@ +module "label7a" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + } +} + +module "label7" { + source = "../../" + + attributes = ["nodegroup"] + + context = module.label7a.context +} + + +output "label7" { + value = { + id = module.label7.id + name = module.label7.name + namespace = module.label7.namespace + stage = module.label7.stage + attributes = module.label7.attributes + delimiter = module.label7.delimiter + } +} + +output "label7_id" { + value = module.label7.id +} + +output "label7_attributes" { + value = module.label7.attributes +} + +output "label7_context" { + value = module.label7.context +} diff --git a/.terraform/modules/this/examples/complete/label8d.tf b/.terraform/modules/this/examples/complete/label8d.tf new file mode 100755 index 0000000..4252419 --- /dev/null +++ b/.terraform/modules/this/examples/complete/label8d.tf @@ -0,0 +1,44 @@ +module "label8d" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8d_context" { + source = "../../" + + context = module.label8d.context +} + +output "label8d_context_id" { + value = module.label8d_context.id +} + +output "label8d_context_context" { + value = module.label8d_context.context +} + +output "label8d_context_tags" { + value = module.label8d_context.tags +} + +output "label8d_id" { + value = module.label8d.id +} + +output "label8d_context" { + value = module.label8d.context +} + +output "label8d_tags" { + value = module.label8d.tags +} diff --git a/.terraform/modules/this/examples/complete/label8dcd.tf b/.terraform/modules/this/examples/complete/label8dcd.tf new file mode 100755 index 0000000..ccdae21 --- /dev/null +++ b/.terraform/modules/this/examples/complete/label8dcd.tf @@ -0,0 +1,24 @@ +module "label8dcd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "x" +} + +module "label8dcd_context" { + source = "../../" + + context = module.label8dcd.context +} + +output "label8dcd_context_id" { + value = module.label8dcd_context.id +} + +output "label8dcd_id" { + value = module.label8dcd.id +} diff --git a/.terraform/modules/this/examples/complete/label8dnd.tf b/.terraform/modules/this/examples/complete/label8dnd.tf new file mode 100755 index 0000000..2edb378 --- /dev/null +++ b/.terraform/modules/this/examples/complete/label8dnd.tf @@ -0,0 +1,24 @@ +module "label8dnd" { + source = "../../" + + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "" +} + +module "label8dnd_context" { + source = "../../" + + context = module.label8dnd.context +} + +output "label8dnd_context_id" { + value = module.label8dnd_context.id +} + +output "label8dnd_id" { + value = module.label8dnd.id +} diff --git a/.terraform/modules/this/examples/complete/label8l.tf b/.terraform/modules/this/examples/complete/label8l.tf new file mode 100755 index 0000000..7462f9e --- /dev/null +++ b/.terraform/modules/this/examples/complete/label8l.tf @@ -0,0 +1,46 @@ +module "label8l" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "lower" + label_value_case = "lower" + + tags = { + "kubernetes.io/cluster/" = "shared" + "upperTEST" = "testUPPER" + } +} + +module "label8l_context" { + source = "../../" + + context = module.label8l.context +} + +output "label8l_context_id" { + value = module.label8l_context.id +} + +output "label8l_context_context" { + value = module.label8l_context.context +} + +output "label8l_context_tags" { + value = module.label8l_context.tags +} + +output "label8l_id" { + value = module.label8l.id +} + +output "label8l_context" { + value = module.label8l.context +} + +output "label8l_tags" { + value = module.label8l.tags +} diff --git a/.terraform/modules/this/examples/complete/label8n.tf b/.terraform/modules/this/examples/complete/label8n.tf new file mode 100755 index 0000000..fd4ad57 --- /dev/null +++ b/.terraform/modules/this/examples/complete/label8n.tf @@ -0,0 +1,45 @@ +module "label8n" { + source = "../../" + + enabled = true + namespace = "EG" + environment = "demo" + name = "blue" + attributes = ["eks", "ClusteR"] + delimiter = "-" + label_value_case = "none" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8n_context" { + source = "../../" + + context = module.label8n.context +} + +output "label8n_context_id" { + value = module.label8n_context.id +} + +output "label8n_context_context" { + value = module.label8n_context.context +} + +output "label8n_context_tags" { + value = module.label8n_context.tags +} + +output "label8n_id" { + value = module.label8n.id +} + +output "label8n_context" { + value = module.label8n.context +} + +output "label8n_tags" { + value = module.label8n.tags +} diff --git a/.terraform/modules/this/examples/complete/label8t.tf b/.terraform/modules/this/examples/complete/label8t.tf new file mode 100755 index 0000000..cb54c7a --- /dev/null +++ b/.terraform/modules/this/examples/complete/label8t.tf @@ -0,0 +1,45 @@ +module "label8t" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["EKS", "cluster"] + delimiter = "-" + label_key_case = "title" + label_value_case = "title" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8t_context" { + source = "../../" + + context = module.label8t.context +} + +output "label8t_context_id" { + value = module.label8t_context.id +} + +output "label8t_context_context" { + value = module.label8t_context.context +} + +output "label8t_context_tags" { + value = module.label8t_context.tags +} + +output "label8t_id" { + value = module.label8t.id +} + +output "label8t_context" { + value = module.label8t.context +} + +output "label8t_tags" { + value = module.label8t.tags +} diff --git a/.terraform/modules/this/examples/complete/label8u.tf b/.terraform/modules/this/examples/complete/label8u.tf new file mode 100755 index 0000000..499535b --- /dev/null +++ b/.terraform/modules/this/examples/complete/label8u.tf @@ -0,0 +1,50 @@ +module "label8u" { + source = "../../" + enabled = true + namespace = "eg" + environment = "demo" + name = "blue" + attributes = ["cluster"] + delimiter = "-" + label_key_case = "upper" + label_value_case = "upper" + + tags = { + "kubernetes.io/cluster/" = "shared" + } +} + +module "label8u_context" { + source = "../../" + + context = module.label8u.context +} + +output "label8u_context_id" { + value = module.label8u_context.id +} + +output "label8u_context_context" { + value = module.label8u_context.context +} + +// debug +output "label8u_context_normalized_context" { + value = module.label8u_context.normalized_context +} + +output "label8u_context_tags" { + value = module.label8u_context.tags +} + +output "label8u_id" { + value = module.label8u.id +} + +output "label8u_context" { + value = module.label8u.context +} + +output "label8u_tags" { + value = module.label8u.tags +} diff --git a/.terraform/modules/this/examples/complete/versions.tf b/.terraform/modules/this/examples/complete/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/this/examples/complete/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/modules/this/exports/context.tf b/.terraform/modules/this/exports/context.tf new file mode 100755 index 0000000..81f99b4 --- /dev/null +++ b/.terraform/modules/this/exports/context.tf @@ -0,0 +1,202 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/.terraform/modules/this/main.tf b/.terraform/modules/this/main.tf new file mode 100755 index 0000000..0deda2b --- /dev/null +++ b/.terraform/modules/this/main.tf @@ -0,0 +1,146 @@ +locals { + + defaults = { + label_order = ["namespace", "environment", "stage", "name", "attributes"] + regex_replace_chars = "/[^-a-zA-Z0-9]/" + delimiter = "-" + replacement = "" + id_length_limit = 0 + id_hash_length = 5 + label_key_case = "title" + label_value_case = "lower" + } + + # So far, we have decided not to allow overriding replacement or id_hash_length + replacement = local.defaults.replacement + id_hash_length = local.defaults.id_hash_length + + # The values provided by variables supersede the values inherited from the context object, + # except for tags and attributes which are merged. + input = { + # It would be nice to use coalesce here, but we cannot, because it + # is an error for all the arguments to coalesce to be empty. + enabled = var.enabled == null ? var.context.enabled : var.enabled + namespace = var.namespace == null ? var.context.namespace : var.namespace + environment = var.environment == null ? var.context.environment : var.environment + stage = var.stage == null ? var.context.stage : var.stage + name = var.name == null ? var.context.name : var.name + delimiter = var.delimiter == null ? var.context.delimiter : var.delimiter + # modules tack on attributes (passed by var) to the end of the list (passed by context) + attributes = compact(distinct(concat(coalesce(var.context.attributes, []), coalesce(var.attributes, [])))) + tags = merge(var.context.tags, var.tags) + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + label_order = var.label_order == null ? var.context.label_order : var.label_order + regex_replace_chars = var.regex_replace_chars == null ? var.context.regex_replace_chars : var.regex_replace_chars + id_length_limit = var.id_length_limit == null ? var.context.id_length_limit : var.id_length_limit + label_key_case = var.label_key_case == null ? lookup(var.context, "label_key_case", null) : var.label_key_case + label_value_case = var.label_value_case == null ? lookup(var.context, "label_value_case", null) : var.label_value_case + } + + + enabled = local.input.enabled + regex_replace_chars = coalesce(local.input.regex_replace_chars, local.defaults.regex_replace_chars) + + # string_label_names are names of inputs that are strings (not list of strings) used as labels + string_label_names = ["name", "namespace", "environment", "stage"] + normalized_labels = { for k in local.string_label_names : k => + local.input[k] == null ? "" : replace(local.input[k], local.regex_replace_chars, local.replacement) + } + normalized_attributes = compact(distinct([for v in local.input.attributes : replace(v, local.regex_replace_chars, local.replacement)])) + + formatted_labels = { for k in local.string_label_names : k => local.label_value_case == "none" ? local.normalized_labels[k] : + local.label_value_case == "title" ? title(lower(local.normalized_labels[k])) : + local.label_value_case == "upper" ? upper(local.normalized_labels[k]) : lower(local.normalized_labels[k]) + } + + attributes = compact(distinct([ + for v in local.normalized_attributes : (local.label_value_case == "none" ? v : + local.label_value_case == "title" ? title(lower(v)) : + local.label_value_case == "upper" ? upper(v) : lower(v)) + ])) + + name = local.formatted_labels["name"] + namespace = local.formatted_labels["namespace"] + environment = local.formatted_labels["environment"] + stage = local.formatted_labels["stage"] + + delimiter = local.input.delimiter == null ? local.defaults.delimiter : local.input.delimiter + label_order = local.input.label_order == null ? local.defaults.label_order : coalescelist(local.input.label_order, local.defaults.label_order) + id_length_limit = local.input.id_length_limit == null ? local.defaults.id_length_limit : local.input.id_length_limit + label_key_case = local.input.label_key_case == null ? local.defaults.label_key_case : local.input.label_key_case + label_value_case = local.input.label_value_case == null ? local.defaults.label_value_case : local.input.label_value_case + + additional_tag_map = merge(var.context.additional_tag_map, var.additional_tag_map) + + tags = merge(local.generated_tags, local.input.tags) + + tags_as_list_of_maps = flatten([ + for key in keys(local.tags) : merge( + { + key = key + value = local.tags[key] + }, var.additional_tag_map) + ]) + + tags_context = { + # For AWS we need `Name` to be disambiguated since it has a special meaning + name = local.id + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = local.id_context.attributes + } + + generated_tags = { + for l in keys(local.tags_context) : + local.label_key_case == "upper" ? upper(l) : ( + local.label_key_case == "lower" ? lower(l) : title(lower(l)) + ) => local.tags_context[l] if length(local.tags_context[l]) > 0 + } + + id_context = { + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + attributes = join(local.delimiter, local.attributes) + } + + labels = [for l in local.label_order : local.id_context[l] if length(local.id_context[l]) > 0] + + id_full = join(local.delimiter, local.labels) + # Create a truncated ID if needed + delimiter_length = length(local.delimiter) + # Calculate length of normal part of ID, leaving room for delimiter and hash + id_truncated_length_limit = local.id_length_limit - (local.id_hash_length + local.delimiter_length) + # Truncate the ID and ensure a single (not double) trailing delimiter + id_truncated = local.id_truncated_length_limit <= 0 ? "" : "${trimsuffix(substr(local.id_full, 0, local.id_truncated_length_limit), local.delimiter)}${local.delimiter}" + # Support usages that disallow numeric characters. Would prefer tr 0-9 q-z but Terraform does not support it. + id_hash_plus = "${md5(local.id_full)}qrstuvwxyz" + id_hash_case = local.label_value_case == "title" ? title(local.id_hash_plus) : local.label_value_case == "upper" ? upper(local.id_hash_plus) : local.label_value_case == "lower" ? lower(local.id_hash_plus) : local.id_hash_plus + id_hash = replace(local.id_hash_case, local.regex_replace_chars, local.replacement) + # Create the short ID by adding a hash to the end of the truncated ID + id_short = substr("${local.id_truncated}${local.id_hash}", 0, local.id_length_limit) + id = local.id_length_limit != 0 && length(local.id_full) > local.id_length_limit ? local.id_short : local.id_full + + + # Context of this label to pass to other label modules + output_context = { + enabled = local.enabled + name = local.name + namespace = local.namespace + environment = local.environment + stage = local.stage + delimiter = local.delimiter + attributes = local.attributes + tags = local.tags + additional_tag_map = local.additional_tag_map + label_order = local.label_order + regex_replace_chars = local.regex_replace_chars + id_length_limit = local.id_length_limit + label_key_case = local.label_key_case + label_value_case = local.label_value_case + } + +} diff --git a/.terraform/modules/this/outputs.tf b/.terraform/modules/this/outputs.tf new file mode 100755 index 0000000..87ad1be --- /dev/null +++ b/.terraform/modules/this/outputs.tf @@ -0,0 +1,88 @@ +output "id" { + value = local.enabled ? local.id : "" + description = "Disambiguated ID restricted to `id_length_limit` characters in total" +} + +output "id_full" { + value = local.enabled ? local.id_full : "" + description = "Disambiguated ID not restricted in length" +} + +output "enabled" { + value = local.enabled + description = "True if module is enabled, false otherwise" +} + +output "namespace" { + value = local.enabled ? local.namespace : "" + description = "Normalized namespace" +} + +output "environment" { + value = local.enabled ? local.environment : "" + description = "Normalized environment" +} + +output "name" { + value = local.enabled ? local.name : "" + description = "Normalized name" +} + +output "stage" { + value = local.enabled ? local.stage : "" + description = "Normalized stage" +} + +output "delimiter" { + value = local.enabled ? local.delimiter : "" + description = "Delimiter between `namespace`, `environment`, `stage`, `name` and `attributes`" +} + +output "attributes" { + value = local.enabled ? local.attributes : [] + description = "List of attributes" +} + +output "tags" { + value = local.enabled ? local.tags : {} + description = "Normalized Tag map" +} + +output "additional_tag_map" { + value = local.additional_tag_map + description = "The merged additional_tag_map" +} + +output "label_order" { + value = local.label_order + description = "The naming order actually used to create the ID" +} + +output "regex_replace_chars" { + value = local.regex_replace_chars + description = "The regex_replace_chars actually used to create the ID" +} + +output "id_length_limit" { + value = local.id_length_limit + description = "The id_length_limit actually used to create the ID, with `0` meaning unlimited" +} + +output "tags_as_list_of_maps" { + value = local.tags_as_list_of_maps + description = "Additional tags as a list of maps, which can be used in several AWS resources" +} + +output "normalized_context" { + value = local.output_context + description = "Normalized context of this module" +} + +output "context" { + value = local.input + description = <<-EOT + Merged but otherwise unmodified input to this module, to be used as context input to other modules. + Note: this version will have null values as defaults, not the values actually used as defaults. +EOT +} + diff --git a/.terraform/modules/this/test/Makefile b/.terraform/modules/this/test/Makefile new file mode 100755 index 0000000..ea15d62 --- /dev/null +++ b/.terraform/modules/this/test/Makefile @@ -0,0 +1,43 @@ +TEST_HARNESS ?= https://github.com/cloudposse/test-harness.git +TEST_HARNESS_BRANCH ?= master +TEST_HARNESS_PATH = $(realpath .test-harness) +BATS_ARGS ?= --tap +BATS_LOG ?= test.log + +# Define a macro to run the tests +define RUN_TESTS +@echo "Running tests in $(1)" +@cd $(1) && bats $(BATS_ARGS) $(addsuffix .bats,$(addprefix $(TEST_HARNESS_PATH)/test/terraform/,$(TESTS))) +endef + +default: all + +-include Makefile.* + +## Provision the test-harnesss +.test-harness: + [ -d $@ ] || git clone --depth=1 -b $(TEST_HARNESS_BRANCH) $(TEST_HARNESS) $@ + +## Initialize the tests +init: .test-harness + +## Install all dependencies (OS specific) +deps:: + @exit 0 + +## Clean up the test harness +clean: + [ "$(TEST_HARNESS_PATH)" == "/" ] || rm -rf $(TEST_HARNESS_PATH) + +## Run all tests +all: module examples/complete + +## Run basic sanity checks against the module itself +module: export TESTS ?= installed lint get-modules module-pinning get-plugins provider-pinning validate terraform-docs input-descriptions output-descriptions +module: deps + $(call RUN_TESTS, ../) + +## Run tests against example +examples/complete: export TESTS ?= installed lint get-modules get-plugins validate init plan apply +examples/complete: deps + $(call RUN_TESTS, ../$@) diff --git a/.terraform/modules/this/test/Makefile.alpine b/.terraform/modules/this/test/Makefile.alpine new file mode 100755 index 0000000..7925b18 --- /dev/null +++ b/.terraform/modules/this/test/Makefile.alpine @@ -0,0 +1,5 @@ +ifneq (,$(wildcard /sbin/apk)) +## Install all dependencies for alpine +deps:: init + @apk add --update terraform-docs@cloudposse json2hcl@cloudposse +endif diff --git a/.terraform/modules/this/test/src/Makefile b/.terraform/modules/this/test/src/Makefile new file mode 100755 index 0000000..b772822 --- /dev/null +++ b/.terraform/modules/this/test/src/Makefile @@ -0,0 +1,30 @@ +export TF_CLI_ARGS_init ?= -get-plugins=true +export TERRAFORM_VERSION ?= $(shell curl -s https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r -M '.current_version' | cut -d. -f1-2) + +.DEFAULT_GOAL : all +.PHONY: all + +## Default target +all: test + +.PHONY : init +## Initialize tests +init: + @exit 0 + +.PHONY : test +## Run tests +test: init + go mod download + go test -v -timeout 60m -run TestExamplesComplete + +## Run tests in docker container +docker/test: + docker run --name terratest --rm -it -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e GITHUB_TOKEN \ + -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" \ + -v $(CURDIR)/../../:/module/ cloudposse/test-harness:latest -C /module/test/src test + +.PHONY : clean +## Clean up files +clean: + rm -rf ../../examples/complete/*.tfstate* diff --git a/.terraform/modules/this/test/src/examples_complete_test.go b/.terraform/modules/this/test/src/examples_complete_test.go new file mode 100755 index 0000000..156e293 --- /dev/null +++ b/.terraform/modules/this/test/src/examples_complete_test.go @@ -0,0 +1,293 @@ +package test + +import ( + "fmt" + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" + "github.com/qdm12/reprint" + "github.com/stretchr/testify/assert" +) + +type NLContext struct { + AdditionalTagMap map[string]string `json:"additional_tag_map"` + Attributes []string `json:"attributes"` + Delimiter interface{} `json:"delimiter"` + Enabled bool `json:"enabled"` + Environment interface{} `json:"environment"` + LabelOrder []string `json:"label_order"` + Name interface{} `json:"name"` + Namespace interface{} `json:"namespace"` + RegexReplaceChars interface{} `json:"regex_replace_chars"` + Stage interface{} `json:"stage"` + Tags map[string]string `json:"tags"` +} + +// Test the Terraform module in examples/complete using Terratest. +func TestExamplesComplete(t *testing.T) { + t.Parallel() + + terraformOptions := &terraform.Options{ + // The path to where our Terraform code is located + TerraformDir: "../../examples/complete", + Upgrade: true, + } + + // At the end of the test, run `terraform destroy` to clean up any resources that were created + defer terraform.Destroy(t, terraformOptions) + + // This will run `terraform init` and `terraform apply` and fail the test if there are any errors + terraform.InitAndApply(t, terraformOptions) + + expectedLabel1Context := NLContext{ + Enabled: true, + Namespace: "CloudPosse", + Environment: "UAT", + Stage: "build", + Name: "Winston Churchroom", + Attributes: []string{"fire", "water", "earth", "air"}, + Delimiter: "-", + LabelOrder: []string{"name", "environment", "stage", "attributes"}, + Tags: map[string]string{ + "City": "Dublin", + "Environment": "Private", + }, + AdditionalTagMap: map[string]string{}, + } + + var expectedLabel1NormalizedContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel1NormalizedContext) + expectedLabel1NormalizedContext.Namespace = "cloudposse" + expectedLabel1NormalizedContext.Environment = "uat" + expectedLabel1NormalizedContext.Name = "winstonchurchroom" + expectedLabel1NormalizedContext.RegexReplaceChars = "/[^-a-zA-Z0-9]/" + expectedLabel1NormalizedContext.Tags = map[string]string{ + "City": "Dublin", + "Environment": "Private", + "Namespace": "cloudposse", + "Stage": "build", + "Name": "winstonchurchroom-uat-build-fire-water-earth-air", + "Attributes": "fire-water-earth-air", + } + + var label1NormalizedContext, label1Context NLContext + // Run `terraform output` to get the value of an output variable + label1 := terraform.OutputMap(t, terraformOptions, "label1") + label1Tags := terraform.OutputMap(t, terraformOptions, "label1_tags") + terraform.OutputStruct(t, terraformOptions, "label1_normalized_context", &label1NormalizedContext) + terraform.OutputStruct(t, terraformOptions, "label1_context", &label1Context) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1["id"]) + assert.Equal(t, "winstonchurchroom-uat-build-fire-water-earth-air", label1Tags["Name"]) + assert.Equal(t, "Dublin", label1Tags["City"]) + assert.Equal(t, "Private", label1Tags["Environment"]) + assert.Equal(t, expectedLabel1NormalizedContext, label1NormalizedContext) + assert.Equal(t, expectedLabel1Context, label1Context) + + label1t1 := terraform.OutputMap(t, terraformOptions, "label1t1") + label1t1Tags := terraform.OutputMap(t, terraformOptions, "label1t1_tags") + assert.Equal(t, "winstonchurchroom-uat-6a0b34", label1t1["id"], + "Extra hash character should be added when trailing delimiter is removed") + assert.Equal(t, label1["id"], label1t1["id_full"], "id_full should not be truncated") + assert.Equal(t, label1t1["id"], label1t1Tags["Name"], "Name tag should match ID") + + label1t2 := terraform.OutputMap(t, terraformOptions, "label1t2") + label1t2Tags := terraform.OutputMap(t, terraformOptions, "label1t2_tags") + assert.Equal(t, "winstonchurchroom-uat-b-6a0b3", label1t2["id"]) + assert.Equal(t, label1t2["id"], label1t2Tags["Name"], "Name tag should match ID") + + // Run `terraform output` to get the value of an output variable + label2 := terraform.OutputMap(t, terraformOptions, "label2") + label2Tags := terraform.OutputMap(t, terraformOptions, "label2_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2["id"]) + assert.Equal(t, "charlie+uat+test+fire+water+earth+air", label2Tags["Name"]) + assert.Equal(t, "London", label2Tags["City"]) + assert.Equal(t, "Public", label2Tags["Environment"]) + + var expectedLabel3cContext, label3cContext NLContext + _ = reprint.FromTo(&expectedLabel1Context, &expectedLabel3cContext) + expectedLabel3cContext.Name = "Starfish" + expectedLabel3cContext.Stage = "release" + expectedLabel3cContext.Delimiter = "." + expectedLabel3cContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3cContext.Tags["Eat"] = "Carrot" + expectedLabel3cContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3c := terraform.OutputMap(t, terraformOptions, "label3c") + label3cTags := terraform.OutputMap(t, terraformOptions, "label3c_tags") + terraform.OutputStruct(t, terraformOptions, "label3c_context", &label3cContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3c["id"]) + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3cTags["Name"]) + assert.Equal(t, expectedLabel3cContext, label3cContext) + + var expectedLabel3nContext, label3nContext NLContext + _ = reprint.FromTo(&expectedLabel1NormalizedContext, &expectedLabel3nContext) + expectedLabel3nContext.Name = "Starfish" + expectedLabel3nContext.Stage = "release" + expectedLabel3nContext.Delimiter = "." + expectedLabel3nContext.RegexReplaceChars = "/[^-a-zA-Z0-9.]/" + expectedLabel3nContext.Tags["Eat"] = "Carrot" + expectedLabel3nContext.Tags["Animal"] = "Rabbit" + + // Run `terraform output` to get the value of an output variable + label3n := terraform.OutputMap(t, terraformOptions, "label3n") + label3nTags := terraform.OutputMap(t, terraformOptions, "label3n_tags") + terraform.OutputStruct(t, terraformOptions, "label3n_context", &label3nContext) + + // Verify we're getting back the outputs we expect + assert.Equal(t, "starfish.uat.release.fire.water.earth.air", label3n["id"]) + assert.Equal(t, label1Tags["Name"], label3nTags["Name"], + "Tag from label1 normalized context should overwrite label3n generated tag") + assert.Equal(t, expectedLabel3nContext, label3nContext) + + // Run `terraform output` to get the value of an output variable + label4 := terraform.OutputMap(t, terraformOptions, "label4") + label4Tags := terraform.OutputMap(t, terraformOptions, "label4_tags") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4["id"]) + assert.Equal(t, "cloudposse-uat-big-fat-honking-cluster", label4Tags["Name"]) + + // Run `terraform output` to get the value of an output variable + label5 := terraform.OutputMap(t, terraformOptions, "label5") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "", label5["id"]) + + label6f := terraform.OutputMap(t, terraformOptions, "label6f") + label6fTags := terraform.OutputMap(t, terraformOptions, "label6f_tags") + // Test of setting var.label_key_case = "lower", var.label_value_case = "upper" + assert.Equal(t, "CP~UW2~PRD~NULL-LABEL", label6f["id_full"]) + assert.Equal(t, label6f["id_full"], label6f["id"], "id should not be truncated") + assert.Equal(t, label6f["id"], label6fTags["name"], "Name tag should match ID") + + label6t := terraform.OutputMap(t, terraformOptions, "label6t") + label6tTags := terraform.OutputMap(t, terraformOptions, "label6t_tags") + assert.Equal(t, "CPUW2PRDNULL-LABEL", label6t["id_full"]) + assert.NotEqual(t, label6t["id_full"], label6t["id"], "id should be truncated") + assert.Equal(t, label6t["id"], label6tTags["name"], "Name tag should match ID") + assert.Equal(t, label6t["id_length_limit"], fmt.Sprintf("%d", len(label6t["id"])), + "Truncated ID length should equal length limit") + + label7 := terraform.OutputMap(t, terraformOptions, "label7") + assert.Equal(t, "eg-demo-blue-cluster-nodegroup", label7["id"], "var.attributes should be appended after context.attributes") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter=""` returns expected value of id, context id + label8dndID := terraform.Output(t, terraformOptions, "label8dnd_id") + label8dndContextID := terraform.Output(t, terraformOptions, "label8dnd_context_id") + assert.Equal(t, "egdemobluecluster", label8dndID) + assert.Equal(t, label8dndID, label8dndContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title`, `label_value_case=lower`, `delimiter="x"` returns expected value of id, context id + label8dcdID := terraform.Output(t, terraformOptions, "label8dcd_id") + label8dcdContextID := terraform.Output(t, terraformOptions, "label8dcd_context_id") + assert.Equal(t, "egxdemoxbluexcluster", label8dcdID) + assert.Equal(t, label8dcdID, label8dcdContextID, "ID and context ID should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=lower` returns expected values of id, tags, context tags + label8dExpectedTags := map[string]string{ + "Attributes": "cluster", + "Environment": "demo", + "Name": "eg-demo-blue-cluster", + "Namespace": "eg", + "kubernetes.io/cluster/": "shared", + } + + label8dID := terraform.Output(t, terraformOptions, "label8d_id") + label8dContextID := terraform.Output(t, terraformOptions, "label8d_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8dID) + assert.Equal(t, label8dID, label8dContextID, "ID and context ID should be equal") + + label8dTags := terraform.OutputMap(t, terraformOptions, "label8d_tags") + label8dContextTags := terraform.OutputMap(t, terraformOptions, "label8d_context_tags") + + assert.Exactly(t, label8dExpectedTags, label8dTags, "generated tags are different from expected") + assert.Exactly(t, label8dTags, label8dContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=lower` and `label_value_case=lower` returns expected values of id, tags, context tags + label8lExpectedTags := map[string]string{ + "attributes": "cluster", + "environment": "demo", + "name": "eg-demo-blue-cluster", + "namespace": "eg", + "kubernetes.io/cluster/": "shared", + "upperTEST": "testUPPER", + } + + label8lID := terraform.Output(t, terraformOptions, "label8l_id") + label8lContextID := terraform.Output(t, terraformOptions, "label8l_context_id") + assert.Equal(t, "eg-demo-blue-cluster", label8lID) + assert.Equal(t, label8lID, label8lContextID, "ID and context ID should be equal") + + label8lTags := terraform.OutputMap(t, terraformOptions, "label8l_tags") + label8lContextTags := terraform.OutputMap(t, terraformOptions, "label8l_context_tags") + + assert.Exactly(t, label8lExpectedTags, label8lTags, "generated tags are different from expected") + assert.Exactly(t, label8lTags, label8lContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=title` returns expected values of id, tags, context tags + label8tExpectedTags := map[string]string{ + "Attributes": "Eks-Cluster", + "Environment": "Demo", + "Name": "Eg-Demo-Blue-Eks-Cluster", + "Namespace": "Eg", + "kubernetes.io/cluster/": "shared", + } + + label8tID := terraform.Output(t, terraformOptions, "label8t_id") + label8tContextID := terraform.Output(t, terraformOptions, "label8t_context_id") + assert.Equal(t, "Eg-Demo-Blue-Eks-Cluster", label8tID) + assert.Equal(t, label8tID, label8tContextID, "ID and context ID should be equal") + + label8tTags := terraform.OutputMap(t, terraformOptions, "label8t_tags") + label8tContextTags := terraform.OutputMap(t, terraformOptions, "label8t_context_tags") + + assert.Exactly(t, label8tExpectedTags, label8tTags, "generated tags are different from expected") + assert.Exactly(t, label8tTags, label8tContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=upper` and `label_value_case=upper` returns expected values of id, tags, context tags + label8uExpectedTags := map[string]string{ + "ATTRIBUTES": "CLUSTER", + "ENVIRONMENT": "DEMO", + "NAME": "EG-DEMO-BLUE-CLUSTER", + "NAMESPACE": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8uID := terraform.Output(t, terraformOptions, "label8u_id") + label8uContextID := terraform.Output(t, terraformOptions, "label8u_context_id") + assert.Equal(t, "EG-DEMO-BLUE-CLUSTER", label8uID) + assert.Equal(t, label8uID, label8uContextID, "ID and context ID should be equal") + + label8uTags := terraform.OutputMap(t, terraformOptions, "label8u_tags") + label8uContextTags := terraform.OutputMap(t, terraformOptions, "label8u_context_tags") + + assert.Exactly(t, label8uExpectedTags, label8uTags, "generated tags are different from expected") + assert.Exactly(t, label8uTags, label8uContextTags, "tags and context tags should be equal") + + // Verify that apply with `label_key_case=title` and `label_value_case=none` returns expected values of id, tags, context tags + label8nExpectedTags := map[string]string{ + "Attributes": "eks-ClusteR", + "Environment": "demo", + "Name": "EG-demo-blue-eks-ClusteR", + "Namespace": "EG", + "kubernetes.io/cluster/": "shared", + } + + label8nID := terraform.Output(t, terraformOptions, "label8n_id") + label8nContextID := terraform.Output(t, terraformOptions, "label8n_context_id") + assert.Equal(t, "EG-demo-blue-eks-ClusteR", label8nID) + assert.Equal(t, label8nID, label8nContextID, "ID and context ID should be equal") + + label8nTags := terraform.OutputMap(t, terraformOptions, "label8n_tags") + label8nContextTags := terraform.OutputMap(t, terraformOptions, "label8n_context_tags") + + assert.Exactly(t, label8nExpectedTags, label8nTags, "generated tags are different from expected") + assert.Exactly(t, label8nTags, label8nContextTags, "tags and context tags should be equal") +} diff --git a/.terraform/modules/this/test/src/go.mod b/.terraform/modules/this/test/src/go.mod new file mode 100755 index 0000000..d866541 --- /dev/null +++ b/.terraform/modules/this/test/src/go.mod @@ -0,0 +1,9 @@ +module github.com/cloudposse/terraform-null-label + +go 1.14 + +require ( + github.com/gruntwork-io/terratest v0.31.1 + github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 + github.com/stretchr/testify v1.6.1 +) diff --git a/.terraform/modules/this/test/src/go.sum b/.terraform/modules/this/test/src/go.sum new file mode 100755 index 0000000..b8d46b1 --- /dev/null +++ b/.terraform/modules/this/test/src/go.sum @@ -0,0 +1,595 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= +github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.5/go.mod h1:foo3aIXRQ90zFve3r0QiDsrjGDUwWhKl0ZOQy1CT14k= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= +github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200109221225-a4f60165b7a3/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= +github.com/gruntwork-io/terratest v0.31.1 h1:MPGe/5pGgJAIZ/hb+0LM1KyJKSi/QyxSkHoP9/CBhJg= +github.com/gruntwork-io/terratest v0.31.1/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= +github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc= +github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4= +github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= +github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= +k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= +k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= +k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= +k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= +k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= +k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= +k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= +modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/.terraform/modules/this/variables.tf b/.terraform/modules/this/variables.tf new file mode 100755 index 0000000..40fb268 --- /dev/null +++ b/.terraform/modules/this/variables.tf @@ -0,0 +1,157 @@ +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} diff --git a/.terraform/modules/this/versions.tf b/.terraform/modules/this/versions.tf new file mode 100755 index 0000000..450c502 --- /dev/null +++ b/.terraform/modules/this/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.0" +} diff --git a/.terraform/providers/registry.terraform.io/datadog/datadog/3.1.2/darwin_amd64/CHANGELOG.md b/.terraform/providers/registry.terraform.io/datadog/datadog/3.1.2/darwin_amd64/CHANGELOG.md new file mode 100755 index 0000000..14e4565 --- /dev/null +++ b/.terraform/providers/registry.terraform.io/datadog/datadog/3.1.2/darwin_amd64/CHANGELOG.md @@ -0,0 +1,829 @@ +## 3.1.2 (June 24, 2021) + +BUGFIXES: + +- `datadog_integration_aws`: Handle all characters for AWS Role Name. ([#1122](https://github.com/DataDog/terraform-provider-datadog/pull/1122)) + +## 3.1.1 (June 22, 2021) + +IMPROVEMENTS: + +- `datadog_integration_aws_tag_filter`: Remove US only constraint from docs. ([#1118](https://github.com/DataDog/terraform-provider-datadog/pull/1118)) + +BUGFIXES: + +- `datadog_logs_index`: Fix retention_days and daily_limit attributes. ([#1118](https://github.com/DataDog/terraform-provider-datadog/pull/1118)) + +## 3.1.0 (June 17, 2021) + +IMPROVEMENTS: + +- `datadog_logs_index`: Adding missing retention_days and daily_limit parameters. ([#1083](https://github.com/DataDog/terraform-provider-datadog/pull/1083)) Thanks [@DimitryVlasenko](https://github.com/DimitryVlasenko) +- `datadog_dashboard`: Add support for WidgetCustomLink `is_hidden` and `override_label` properties. ([#1062](https://github.com/DataDog/terraform-provider-datadog/pull/1062)) +- `datadog_synthetics_test`: Add support for monitor name and priority. ([#1104](https://github.com/DataDog/terraform-provider-datadog/pull/1104)) +- `datadog_integration_aws`: Add support for access_key_id and secret_access_key. ([#1101](https://github.com/DataDog/terraform-provider-datadog/pull/1101)). +- `datadog_dashboard`: Update dashboard examples. ([#1105](https://github.com/DataDog/terraform-provider-datadog/pull/1105)) +- `datadog_synthetics_test`: Add support for global variables in config variables. ([#1106](https://github.com/DataDog/terraform-provider-datadog/pull/1106)) +- `datadog_dashboard_json`: Add dashboard list support. ([#1102](https://github.com/DataDog/terraform-provider-datadog/pull/1102)) +- `datadog_downtime`: Properly handle recurring downtimes definitions. ([#1092](https://github.com/DataDog/terraform-provider-datadog/pull/1092)) +- `datadog_dashboard`: Dashboard RBAC roles. ([#1109](https://github.com/DataDog/terraform-provider-datadog/pull/1109)) + +BUGFIXES: + +- `datadog_integration_aws`: Properly catch error response from AWS Logs integration. ([#1095](https://github.com/DataDog/terraform-provider-datadog/pull/1095)) +- `datadog_integration_aws`: Handle empty parameters in AWS and Azure integrations. ([#1096](https://github.com/DataDog/terraform-provider-datadog/pull/1096)). +- `datadog_integration_azure`: Handle empty parameters in AWS and Azure integrations. ([#1096](https://github.com/DataDog/terraform-provider-datadog/pull/1096)). +- `datadog_monitor`: Re-introduce monitor type diff suppression for query/metric alerts. ([#1099](https://github.com/DataDog/terraform-provider-datadog/pull/1099)) +- `datadog_synthetics_test`: Allow zero value for dns_server_port. ([#1087](https://github.com/DataDog/terraform-provider-datadog/pull/1087)) + +NOTES: + +- Update Datadog api go client. See [here](https://github.com/DataDog/datadog-api-client-go/releases/tag/v1.1.0) for changes. + +## 3.0.0 (May 27, 2021) + +IMPROVEMENTS: + +- Upgrade terraform-plugin-sdk to v2. See https://www.terraform.io/docs/extend/guides/v2-upgrade-guide.html for all the internal changes. + +NOTES: + +- `datadog_monitor`: Remove the `threshold` deprecated property. +- `datadog_monitor`: Remove the `threshold_windows` deprecated property. +- `datadog_monitor`: Remove the `silenced` deprecated property. +- `datadog_dashboard`: Remove the `layout` deprecated property from widgets. +- `datadog_dashboard`: Remove the `time` deprecated property from widgets. +- `datadog_dashboard`: Remove the `logset` deprecated property from widgets. +- `datadog_dashboard`: Remove the `count` deprecated property from widgets. +- `datadog_dashboard`: Remove the `start` deprecated property from widgets. +- `datadog_dashboard`: Remove the `compute` deprecated property from widgets. +- `datadog_dashboard`: Remove the `search` deprecated property from widgets. +- `datadog_integration_pagerduty`: Remove the `services` deprecated property. +- `datadog_logs_archive`: Remove the `s3` deprecated property. +- `datadog_logs_archive`: Remove the `azure` deprecated property. +- `datadog_logs_archive`: Remove the `gcs` deprecated property. +- `datadog_screenboard`: Remove the deprecated resource +- `datadog_service_level_objective`: Remove the `monitor_search` deprecated property. +- `datadog_timeboard`: Remove the deprecated resource. +- `datadog_synthetics_test`: Remove the `request` deprecated property. +- `datadog_synthetics_test`: Remove the `assertions` deprecated property. +- `datadog_synthetics_test`: Remove the `options` deprecated property. +- `datadog_synthetics_test`: Remove the `step` deprecated property. +- `datadog_synthetics_test`: Remove the `variable` deprecated property. +- `datadog_user`: Remove the `handle` deprecated property. +- `datadog_user`: Remove the `is_admin` deprecated property. +- `datadog_user`: Remove the `access_role` deprecated property. +- `datadog_user`: Remove the `role` deprecated property. + +## 2.26.1 (May 20, 2021) + +BUGFIXES: + +- `datadog_dashboard_json`: Fix `dashboard` attribute retrieval when calling the update method ([#1072](https://github.com/DataDog/terraform-provider-datadog/pull/1072)) + +## 2.26.0 (May 18, 2021) + +IMPROVEMENTS: + +- `datadog_logs_custom_pipeline`: Add mutex to logs custom pipeline resource ([#1069](https://github.com/DataDog/terraform-provider-datadog/pull/1069)) +- `datadog_logs_custom_pipeline`: Use code formatting in description for attribute re-mapper ([#1061](https://github.com/DataDog/terraform-provider-datadog/pull/1061)) +- `datadog_monitor`: Update monitor critical threshold documentation ([#1055](https://github.com/DataDog/terraform-provider-datadog/pull/1055)) +- `datadog_monitor`: Retry on 504's when validating monitors ([#1038](https://github.com/DataDog/terraform-provider-datadog/pull/1038)) +- `datadog_dashboard_json`: Ignore widget IDs for diff on dashboard JSON resource ([#1028](https://github.com/DataDog/terraform-provider-datadog/pull/1028)) +- `datadog_monitor`: Add monitors datasource for multiple monitors ([#1048](https://github.com/DataDog/terraform-provider-datadog/pull/1048)) +- `datadog_synthetics_test`: Add support for setCookie, dnsServerPort, allowFailure and isCritical fields for Synthetics tests ([#1052](https://github.com/DataDog/terraform-provider-datadog/pull/1052)) +- `datadog_dashboard`: Add new properties to group widget, note widget and image widget ([#1044](https://github.com/DataDog/terraform-provider-datadog/pull/1044)) +- `datadog_synthetics_test`: Add support for icmp tests ([#1030](https://github.com/DataDog/terraform-provider-datadog/pull/1030)) +- `datadog_dashboard`: Implement formulas and functions for geomap widgets ([#1043](https://github.com/DataDog/terraform-provider-datadog/pull/1043)) +- `datadog_dashboard`: Formula and Function support for Toplist Widgets in Dashboard resource ([#951](https://github.com/DataDog/terraform-provider-datadog/pull/951)) +- `datadog_dashboard`: Add reflow_type property for dashboards ([#1017](https://github.com/DataDog/terraform-provider-datadog/pull/1017)) +- `datadog_dashboard`: Formula and Function support for Query Value Widgets in Dashboard resource ([#953](https://github.com/DataDog/terraform-provider-datadog/pull/953)) + +FEATURES: + +- `datadog_service_level_objective`: Add SLO data sources ([#931](https://github.com/DataDog/terraform-provider-datadog/pull/931)) + +BUGFIXES: + +- `datadog_downtime`: Properly mark active/disabled fields as readonly to avoid diffs ([#1034](https://github.com/DataDog/terraform-provider-datadog/pull/1034)) +- `datadog_integration_aws`: Mark AWS account as non existent if GET returns 400 when AWS integration not installed ([#1047](https://github.com/DataDog/terraform-provider-datadog/pull/1047)) + +NOTES: + +- Use custom transport for HTTPClient to enable retries on 429 and 5xx http errors ([#1054](https://github.com/DataDog/terraform-provider-datadog/pull/1054)) +- Update Datadog api go client. See [here](https://github.com/DataDog/datadog-api-client-go/releases/tag/v1.0.0-beta.22) for changes. + +## 2.25.0 (April 15, 2021) + +IMPROVEMENTS: + +- `datadog_slo_correction`: Add docs for SLO Correction resource ([#1021](https://github.com/DataDog/terraform-provider-datadog/pull/1021)) +- `datadog_synthetics_test`: Use new API models for api tests ([#1005](https://github.com/DataDog/terraform-provider-datadog/pull/1005)) +- `datadog_monitor`: Improve consistency by using response from POST/PUT requests ([#1015](https://github.com/DataDog/terraform-provider-datadog/pull/1015)) +- `datadog_synthetics_test`: Add `noSavingResponseBody` and `noScreenshot` fields ([#1012](https://github.com/DataDog/terraform-provider-datadog/pull/1012)) +- `datadog_logs_metric`: Add `group_by` block to logs_metric example ([#1010](https://github.com/DataDog/terraform-provider-datadog/pull/1010)) + +FEATURES: + +- `datadog_dashboard`: Add support for Formula and Function support for Timeseries Widgets ([#892](https://github.com/DataDog/terraform-provider-datadog/pull/892)) +- `datadog_synthetics_test`: Add support for `multi` step synthetics API tests ([#1007](https://github.com/DataDog/terraform-provider-datadog/pull/1007)) +- `datadog_security_monitoring_default_rule`: Add datadog default security monitoring rule filters ([#965](https://github.com/DataDog/terraform-provider-datadog/pull/965)) +- `datadog_synthetics_test`: Add support for global_time_target for SLO widgets ([#1003](https://github.com/DataDog/terraform-provider-datadog/pull/1003)) + +BUGFIXES: + +- `datadog_synthetics_test`: Set `tick_every` as required and add default value for `example` field ([#1020](https://github.com/DataDog/terraform-provider-datadog/pull/1020)) +- `datadog_monitor`: Fix diff suppression for field `restricted_roles` ([#1011](https://github.com/DataDog/terraform-provider-datadog/pull/1011)) +- `datadog_integration_slack_channel`: Fix `account_id` field not being set on imports ([#1019](https://github.com/DataDog/terraform-provider-datadog/pull/1019)) +- `datadog_synthetics_test`: Fix error when passing empty step param ([#1014](https://github.com/DataDog/terraform-provider-datadog/pull/1014)) +- `datadog_integration_gcp`: Set ForceNew to true on non-updatable GCP resource fields ([#1014](https://github.com/DataDog/terraform-provider-datadog/pull/1007)) +- `datadog_dashboard`: Add retry on 502's when listing dashbaord ([#1006](https://github.com/DataDog/terraform-provider-datadog/pull/1006)) + +NOTES: + +- Update the underlying Datadog go client to v1.0.0-beta.19. See [here](https://github.com/DataDog/datadog-api-client-go/releases/tag/v1.0.0-beta.19) for changes. + +## 2.24.0 (March 22, 2021) + +IMPROVEMENTS: + +- `datadog_dashboard`: Add `legend_layout` and `legend_columns` to timeseries widget definition ([#992](https://github.com/Datadog/terraform-provider-datadog/pull/992)). + +FEATURES: + +- `datadog_metric_tag_configuration` Add new resource ([#960](https://github.com/Datadog/terraform-provider-datadog/pull/960)). + +## 2.23.0 (March 16, 2021) + +IMPROVEMENTS: + +- `datadog_dashboard`: Implement support for Geomap Dashboard Widget ([#954](https://github.com/Datadog/terraform-provider-datadog/pull/954)). + +FEATURES: + +- `datadog_dashboard_json`: Add new dashboard JSON resource ([#950](https://github.com/Datadog/terraform-provider-datadog/pull/950)). + +BUGFIXES: + +- `datadog_dashboard`: Add a retry on 504 errors when there is a timeout ([#975](https://github.com/Datadog/terraform-provider-datadog/pull/975)). +- `datadog_integration_slack_channel`: Fix issue causing slack channels to not be created in some situations ([#981](https://github.com/Datadog/terraform-provider-datadog/pull/981)). +- `datadog_monitor`: Explicitly check `monitor_id` for `nil` value to fix an issue with terraformer ([#962](https://github.com/Datadog/terraform-provider-datadog/pull/962)). +- `datadog_security_monitoring_default_rule`: Fix issue that prevented default rule cases notifications to be updated ([#956](https://github.com/Datadog/terraform-provider-datadog/pull/956)). + +NOTES: + +- Update the underlying Datadog go client to v1.0.0-beta.17. See [here](https://github.com/DataDog/datadog-api-client-go/releases/tag/v1.0.0-beta.17) for changes. + +## 2.22.0 (March 3, 2021). + +IMPROVEMENTS: + +- `datadog_dashboard`: Improve consistency by using response from POST/PUT requests directly to save state ([#909](https://github.com/Datadog/terraform-provider-datadog/pull/909)). +- `datadog_downtime`: Improve consistency by using response from POST/PUT requests directly to save state ([#905](https://github.com/Datadog/terraform-provider-datadog/pull/905)). +- `datadog_ip_ranges`: Add support for reading ipv4/6 prefixes by location for synthetics ([#934](https://github.com/Datadog/terraform-provider-datadog/pull/934)). +- `datadog_logs_archive_order`: Improve consistency by using response from POST/PUT requests directly to save state ([#912](https://github.com/Datadog/terraform-provider-datadog/pull/912)). +- `datadog_logs_archive`: Improve consistency by using response from POST/PUT requests directly to save state ([#912](https://github.com/Datadog/terraform-provider-datadog/pull/912)). +- `datadog_logs_custom_pipeline`: Improve consistency by using response from POST/PUT requests directly to save state ([#913](https://github.com/Datadog/terraform-provider-datadog/pull/913)). +- `datadog_logs_index_order`: Improve consistency by using response from POST/PUT requests directly to save state ([#915](https://github.com/Datadog/terraform-provider-datadog/pull/915)). +- `datadog_logs_index`: Improve consistency by using response from POST/PUT requests directly to save state ([#915](https://github.com/Datadog/terraform-provider-datadog/pull/915)). +- `datadog_logs_integration_pipeline`: Improve consistency by using response from POST/PUT requests directly to save state ([#913](https://github.com/Datadog/terraform-provider-datadog/pull/913)). +- `datadog_logs_metric`: Improve consistency by using response from POST/PUT requests directly to save state ([#917](https://github.com/Datadog/terraform-provider-datadog/pull/917)). +- `datadog_logs_pipeline_order`: Improve consistency by using response from POST/PUT requests directly to save state ([#913](https://github.com/Datadog/terraform-provider-datadog/pull/913)). +- `datadog_metric_metadata`: Improve consistency by using response from POST/PUT requests directly to save state ([#922](https://github.com/Datadog/terraform-provider-datadog/pull/922)). +- `datadog_monitor`: Add support for `groupby_simple_monitor` option to monitor resource ([#952](https://github.com/Datadog/terraform-provider-datadog/pull/952)). +- `datadog_monitor`: Improve consistency by using response from POST/PUT requests directly to save state ([#901](https://github.com/Datadog/terraform-provider-datadog/pull/901)). +- `datadog_role`: Improve consistency by using response from POST/PUT requests directly to save state ([#925](https://github.com/Datadog/terraform-provider-datadog/pull/925)). +- `datadog_service_level_objective`: Improve consistency by using response from POST/PUT requests directly to save state ([#910](https://github.com/Datadog/terraform-provider-datadog/pull/910)). +- `datadog_slo_correction`: Improve consistency by using response from POST/PUT requests directly to save state ([#921](https://github.com/Datadog/terraform-provider-datadog/pull/921)). +- `datadog_user`: Improve consistency by using response from POST/PUT requests directly to save state ([#927](https://github.com/Datadog/terraform-provider-datadog/pull/927)). + +FEATURES: + +- `datadog_integration_slack_channel`: Add support for slack channel resource ([#932](https://github.com/Datadog/terraform-provider-datadog/pull/932)). + +BUGFIXES: + +- `datadog_dashboard`: Fix template_variable_presets to support optional template_variables ([#944](https://github.com/Datadog/terraform-provider-datadog/pull/944)). + +NOTES: + +- `datadog_integration_pagerduty`: Remove deprecation on PagerDuty resource ([#930](https://github.com/Datadog/terraform-provider-datadog/pull/930)). +- Update the underlying Datadog go client to v1.0.0-beta.16. See [here](https://github.com/DataDog/datadog-api-client-go/releases/tag/v1.0.0-beta.16) for changes. + +## 2.21.0 (February 9, 2021) + +IMPROVEMENTS: + +- `datadog_integration_aws_filter`: Add new resource ([#881](https://github.com/Datadog/terraform-provider-datadog/pull/881)). +- `datadog_slo_correction`: Add new resource ([#866](https://github.com/Datadog/terraform-provider-datadog/pull/866)). + +FEATURES: + +- `datadog_monitor`: Add restricted roles. ([#883](https://github.com/Datadog/terraform-provider-datadog/pull/883)). +- `datadog_synthetics_test`: Add parameter to prevent useless diffs for browser tests ([#854](https://github.com/Datadog/terraform-provider-datadog/pull/854)). +- `datadog_synthetics_test`: Add new `browser_step` field for browser tests ([#849](https://github.com/Datadog/terraform-provider-datadog/pull/849)). + +BUGFIXES: + +- `datadog_synthetics_global_variable`: Fix setting `parse_test_options` attribute ([#867](https://github.com/Datadog/terraform-provider-datadog/pull/867)). +- `datadog_security_monitoring_rule`: Fix enabled attribute retrieval ([#862](https://github.com/Datadog/terraform-provider-datadog/pull/862)). +- `datadog_metric_metadata`: Fix id retrieval when calling the read function ([#856](https://github.com/Datadog/terraform-provider-datadog/pull/856)). +- `datadog_logs_custom_pipeline`: Support empty strings for filter query ([#855](https://github.com/Datadog/terraform-provider-datadog/pull/855)). +- `datadog_dashboard`: Handle crash in `timeseries_definition` ([#863](https://github.com/Datadog/terraform-provider-datadog/pull/863)). +- `datadog_synthetics_test`: Turn locations into a set ([#864](https://github.com/Datadog/terraform-provider-datadog/pull/864)). + +NOTES: + +- `datadog_dashboard`: Deprecate TypeMap complex fields ([#853](https://github.com/Datadog/terraform-provider-datadog/pull/853)). +- `datadog_synthetics_test`: Deprecate TypeMap field ([#870](https://github.com/Datadog/terraform-provider-datadog/pull/870)). +- `datadog_monitor` : Include SDK when a tag is a unexpected prefix ([#781](https://github.com/DataDog/terraform-provider-datadog/issues/781)). +- Backport performance fix to SDK v1. + +## 2.20.0 (January 20, 2021) + +IMPROVEMENTS: + +- `datadog_logs_metrics`: Add new resource ([#823](https://github.com/Datadog/terraform-provider-datadog/pull/823)). + +FEATURES: + +- `datadog_dashboard`: Store dashboard widget IDs ([#815](https://github.com/Datadog/terraform-provider-datadog/pull/815)). +- `datadog_synthetics_test`: Add support for global variables from test ([#831](https://github.com/Datadog/terraform-provider-datadog/pull/831)). + +BUGFIXES: + +- `datadog_synthetics_test`: Store SHA 256 hash of certificates in state instead of the actual cert ([#835](https://github.com/Datadog/terraform-provider-datadog/pull/835)). + +NOTES: + +- `datadog_user`: Deprecate `access_role` field ([#834](https://github.com/Datadog/terraform-provider-datadog/pull/834)). +- `datadog_monitor`: Provide alternative to TypeMap complex fields ([#833](https://github.com/Datadog/terraform-provider-datadog/pull/833)). +- `datadog_logs_archive`: Provide alternative to TypeMap complex fields ([#838](https://github.com/Datadog/terraform-provider-datadog/pull/838)). + +## 2.19.1 (January 8, 2021) + +BUGFIXES: + +- `datadog_monitor`: Handle 404 properly with retry ([#824](https://github.com/DataDog/terraform-provider-datadog/pull/824)). +- `datadog_integration_aws`: Remove incorrect deprecation warning ([#820](https://github.com/DataDog/terraform-provider-datadog/pull/820)). + +## 2.19.0 (January 7, 2021) + +FEATURES: + +- `datadog_synthetics_test`: Add support for config variables ([#807](https://github.com/DataDog/terraform-provider-datadog/pull/807)). + +BUGFIXES: + +- `datadog_user`: Add ability to send user invitations in v2 API ([#814](https://github.com/DataDog/terraform-provider-datadog/pull/814)). +- `datadog_monitor`: Fix updating priorities. ([#804](https://github.com/DataDog/terraform-provider-datadog/pull/804)). +- `datadog_monitor`: Add retry on 502 for get and validate ([#816](https://github.com/DataDog/terraform-provider-datadog/pull/816)). +- `datadog_synthetics_test`: Fix error when setting status code assertion with regex ([#784](https://github.com/DataDog/terraform-provider-datadog/pull/784)). +- `datadog_logs_index_order`: Enable `UpdateLogsIndexOrder` operation ([#790](https://github.com/DataDog/terraform-provider-datadog/pull/790)). +- Validate enum values ([#794](https://github.com/DataDog/terraform-provider-datadog/pull/794)). + +NOTES: + +- Remove deprecated `ExistsFunc` usage ([#805](https://github.com/DataDog/terraform-provider-datadog/pull/805)). + +## 2.18.1 (December 9, 2020) + +BUGFIXES: + +- `datadog_user`: Automatically upgrade users when `roles` is set ([#778](https://github.com/DataDog/terraform-provider-datadog/pull/778)). +- `datadog_dashboard`: Add ForceNew to `layout_type` dashboard attribute ([#774](https://github.com/DataDog/terraform-provider-datadog/pull/774)). + +## 2.18.0 (December 8, 2020) + +IMPROVEMENTS: + +- `datadog_synthetics_private_location`: Add support for synthetics private locations ([#761](https://github.com/DataDog/terraform-provider-datadog/pull/761)). +- `datadog_security_monitoring_rule`: Add support for security monitoring rules ([#763](https://github.com/DataDog/terraform-provider-datadog/pull/763)). + +FEATURES: + +- `datadog_service_level_objective`: Add `force_delete` attribute, to manage deletion in dashboard references ([#771](https://github.com/DataDog/terraform-provider-datadog/pull/771)). +- `datadog_synthetics_global_variable`: Add support for secure global variables ([#758](https://github.com/DataDog/terraform-provider-datadog/pull/758)). + +BUGFIXES: + +- `datadog_synthetics_test`: Handle numbers in `targetvalue` for synthetics assertions ([#766](https://github.com/DataDog/terraform-provider-datadog/pull/766)). + +NOTES: + +- `datadog_user`: Use v2 API. This deprecates several v1 only attributes ([#752](https://github.com/DataDog/terraform-provider-datadog/pull/752)). + +## 2.17.0 (November 24, 2020) + +FEATURES: + +- `datadog_role`: Add role datasource ([#751](https://github.com/DataDog/terraform-provider-datadog/pull/751)) +- `datadog_role`: Add roles resource and permissions datasource ([#753](https://github.com/DataDog/terraform-provider-datadog/pull/753)). + +BUGFIXES: + +- `datadog_dashboard`: Handle multiple dashboards correctly in the datasource ([#759](https://github.com/DataDog/terraform-provider-datadog/pull/759)). +- `datadog_synthetics_test`: Set client certificate content as sensitive ([#750](https://github.com/DataDog/terraform-provider-datadog/pull/750)). +- `datadog_monitor`: Fix monitor `no_data_timeframe` import ([#748](https://github.com/DataDog/terraform-provider-datadog/pull/748)). + +## 2.16.0 (November 9, 2020) + +IMPROVEMENTS: + +- `datadog_dashboard`: Add new data source ([#734](https://github.com/DataDog/terraform-provider-datadog/pull/734)). + +BUGFIXES: + +- `datadog_dashboard`: Update go client to get new palette values ([#743](https://github.com/DataDog/terraform-provider-datadog/pull/743)). + +## 2.15.0 (November 2, 2020) + +IMPROVEMENTS: + +- `datadog_monitor`: Add `priority`field ([#729](https://github.com/DataDog/terraform-provider-datadog/pull/729)). + +BUGFIXES: + +- `datadog_synthetics_test`: Handle missing variables field from API response ([#733](https://github.com/DataDog/terraform-provider-datadog/pull/733)). +- `datadog_monitor`: Handle `0` in `new_host_delay` ([#726](https://github.com/DataDog/terraform-provider-datadog/pull/726)). + +NOTES: + +- `provider`: Replace 4d63.com/tz with time/tzdata. It means go 1.15 is required now to build the provider ([#728](https://github.com/DataDog/terraform-provider-datadog/pull/728)). + +## 2.14.0 (October 27, 2020) + +FEATURES: + +- `datadog_logs_archive_order`: Add a new resource to reorder logs archives ([#694](https://github.com/DataDog/terraform-provider-datadog/pull/694)). +- `datadog_synthetics_global_variable`: Add a new resource to support global variables in synthetics tests ([#675](https://github.com/DataDog/terraform-provider-datadog/pull/675)). + +IMPROVEMENTS: + +- `datadog_dashboard`: Add support for `apm_stats_query` request type in widgets ([#676](https://github.com/DataDog/terraform-provider-datadog/pull/676)). +- `datadog_dashboard`: Add support for dual y-axis for timeseries widgets ([#685](https://github.com/DataDog/terraform-provider-datadog/pull/685)). +- `datadog_dashboard`: Add support for `has_search_bar` and `cell_display_mode` properties on widgets ([#686](https://github.com/DataDog/terraform-provider-datadog/pull/686)). +- `datadog_dashboard`: Add support for `custom_links` property on widgets ([#696](https://github.com/DataDog/terraform-provider-datadog/pull/696)). +- `datadog_logs_archive`: Add `rehydration_tags` property ([#705](https://github.com/DataDog/terraform-provider-datadog/pull/705)). +- `datadog_logs_archive`: Add `include_tags` property ([#715](https://github.com/DataDog/terraform-provider-datadog/pull/715)). +- `datadog_logs_custom_pipeline`: Add `target_format` property to the Logs attribute remapper ([#682](https://github.com/DataDog/terraform-provider-datadog/pull/682)). +- `datadog_service_level_objective`: Add validate option ([#672](https://github.com/DataDog/terraform-provider-datadog/pull/672)). +- `datadog_synthetics_test`: Add support for DNS tests ([#673](https://github.com/DataDog/terraform-provider-datadog/pull/673)). +- `datadog_synthetics_test`: Add support for global variables ([#691](https://github.com/DataDog/terraform-provider-datadog/pull/691)). +- `datadog_synthetics_test`: Add support for `dns_server` and `request_client_certificate` properties ([#711](https://github.com/DataDog/terraform-provider-datadog/pull/711)). + +BUGFIXES: + +- `datadog_synthetics_test`: Don't ignore options diff ([#707](https://github.com/DataDog/terraform-provider-datadog/pull/707)). +- `datadog_synthetics_test`: Make `tags` property optional ([#712](https://github.com/DataDog/terraform-provider-datadog/pull/712)). +- `datadog_ip_ranges`: Support EU site ([#713](https://github.com/DataDog/terraform-provider-datadog/pull/713)). + +## 2.13.0 (September 16, 2020) + +FEATURES: + +- `datadog_dashboard_list`: Add a new datasource for dashboard lists ([#657](https://github.com/DataDog/terraform-provider-datadog/pull/657)). +- `datadog_synthetics_locations`: Add a new datasource for locations ([#309](https://github.com/DataDog/terraform-provider-datadog/pull/309)). + +IMPROVEMENTS: + +- `datadog_dashboard`: A new `dashboard_lists` attribute allows adding dashboard to dashboard lists in the resource itself ([#654](https://github.com/DataDog/terraform-provider-datadog/pull/654)). +- `datadog_dashboard`: Add support for `multi_compute` attribute ([#629](https://github.com/DataDog/terraform-provider-datadog/pull/629)). +- `datadog_dashboard`: Add support for `metric` in `conditional_formats` ([#617](https://github.com/DataDog/terraform-provider-datadog/pull/617)). +- `datadog_dashboard`: Add support for `rum_query` and `security_query` widget requests ([#416](https://github.com/DataDog/terraform-provider-datadog/pull/416)). +- `datadog_monitor`: Monitors are now validated during plan ([#639](https://github.com/DataDog/terraform-provider-datadog/pull/639)). +- `datadog_downtime`: Add support for recurrent rules ([#610](https://github.com/DataDog/terraform-provider-datadog/pull/610)). +- `datadog_synthetics_test`: Add support for steps for browser tests ([#638](https://github.com/DataDog/terraform-provider-datadog/pull/638)). +- `datadog_synthetics_test`: Add subtype TCP test support for API tests ([#632](https://github.com/DataDog/terraform-provider-datadog/pull/632)). +- `datadog_synthetics_test`: Add retry and monitor options ([#636](https://github.com/DataDog/terraform-provider-datadog/pull/636)). + +BUGFIXES: + +- `datadog_dashboard`: Prevent nil pointer dereference with template variables without prefix ([#630](https://github.com/DataDog/terraform-provider-datadog/pull/630)). +- `datadog_dashboard`: Don't allow empty content in note widgets ([#607](https://github.com/DataDog/terraform-provider-datadog/pull/607)). +- `datadog_downtime`: Ignore useless diff on start attribute ([#597](https://github.com/DataDog/terraform-provider-datadog/pull/597)). +- `datadog_logs_custom_pipeline`: Don't allow empty pipeline filter ([#605](https://github.com/DataDog/terraform-provider-datadog/pull/605)). +- `provider`: Completely skip creds validation when validate is false ([#641](https://github.com/DataDog/terraform-provider-datadog/pull/641)). + +NOTES: + +- `datadog_synthetics_test`: The `options` attribute has been deprecated by `options_list` ([#624](https://github.com/DataDog/terraform-provider-datadog/pull/624)). + +## 2.12.1 (July 23, 2020) + +This release doesn't contain any user-facing changes. It's done as a required part of process to finalize the transfer of the provider repository under DataDog GitHub organization: https://github.com/DataDog/terraform-provider-datadog. + +## 2.12.0 (July 22, 2020) + +FEATURES: + +- `datadog_monitor`: Add new datasource for monitors ([#569](https://github.com/DataDog/terraform-provider-datadog/issues/569)), ([#585](https://github.com/DataDog/terraform-provider-datadog/issues/585)). + +IMPROVEMENTS: + +- `datadog_synthetics_test`: Enable usage of `validatesJSONPath` operator ([#571](https://github.com/DataDog/terraform-provider-datadog/issues/571)). +- `datadog_synthetics_test`: Allow usage of the new assertion format ([#571](https://github.com/DataDog/terraform-provider-datadog/issues/571)), ([#582](https://github.com/DataDog/terraform-provider-datadog/issues/582)). +- `datadog_synthetics_test`: Add support for `basicAuth` and `query` ([#586](https://github.com/DataDog/terraform-provider-datadog/issues/586)). + +BUGFIXES: + +- `datadog_downtime`: Replace `time.LoadLocation` by tz.LoadLocation from `4d63.com/tz` package ([#560](https://github.com/DataDog/terraform-provider-datadog/issues/560)). +- `datadog_downtime`: Use `TypeSet` for monitor tags to avoid unnecessary diffs ([#540](https://github.com/DataDog/terraform-provider-datadog/issues/540)). +- `provider`: Respect the debug setting in the new Go Datadog client ([#580](https://github.com/DataDog/terraform-provider-datadog/issues/580)). + +NOTES: + +- `datadog_integration_pagerduty`: This resource is deprecated. You can use `datadog_integration_pagerduty_service_object` resources directly once the integration is activated ([#584](https://github.com/DataDog/terraform-provider-datadog/issues/584)). + +## 2.11.0 (June 29, 2020) + +FEATURES: + +- `datadog_logs_archive`: Add `datadog_logs_archive` resource ([#544](https://github.com/DataDog/terraform-provider-datadog/pull/544)). +- `datadog_integration_azure`: Add `datadog_integration_azure` resource ([#556](https://github.com/DataDog/terraform-provider-datadog/pull/556)). + +## 2.10.0 (June 26, 2020) + +FEATURES: + +- `datadog_integration_aws`: Add `excluded_regions` parameter ([#549](https://github.com/DataDog/terraform-provider-datadog/pull/549)). +- `datadog_dashboard`: Add `ServiceMap` widget to dashboard ([#550](https://github.com/DataDog/terraform-provider-datadog/pull/550)). +- `datadog_dashboard`: Add `show_legend` and `legend_size` fields to Distribution widget ([#551](https://github.com/DataDog/terraform-provider-datadog/pull/551)). +- `datadog_dashboard`: Add `network_query` and `rum_query` to timeseries widget ([#555](https://github.com/DataDog/terraform-provider-datadog/pull/555)). +- `datadog_dashboard`: Add `event`, `legend_size` and `show_legend` fields to heatmap widget ([#554](https://github.com/DataDog/terraform-provider-datadog/pull/554)). + +IMPROVEMENTS: + +- `datadog_dashboard`: Add readonly url field to dashboard ([#558](https://github.com/DataDog/terraform-provider-datadog/pull/558)). + +## 2.9.0 (June 22, 2020) + +IMPROVEMENTS: + +- `datadog_monitor`: Add monitor `force_delete` parameter ([#535](https://github.com/DataDog/terraform-provider-datadog/pull/535)) Thanks [@ykyr](https://github.com/ykyr) + +BUGFIXES: + +- `datadog_dashboard`: Safely access index field ([#536](https://github.com/DataDog/terraform-provider-datadog/pull/536)) +- `datadog_dashboard`: Set title and title_align properly on heatmap widget ([#539](https://github.com/DataDog/terraform-provider-datadog/pull/539)) +- `datadog_ip_ranges`: Fix data source for IPRanges ([#542](https://github.com/DataDog/terraform-provider-datadog/pull/542)) +- `datadog_monitor`: Fix indent in datadog_monitor docs example ([#543](https://github.com/DataDog/terraform-provider-datadog/pull/543)) Thanks [@nekottyo](https://github.com/nekottyo) + +NOTES: + +- `datadog_synthetics_test`: `SyntheticsDeviceID` should accept all allowed values ([#538](https://github.com/DataDog/terraform-provider-datadog/issues/538)) +- Thanks [@razaj92](https://github.com/razaj92) ([#547](https://github.com/DataDog/terraform-provider-datadog/pull/547)) who contributed to this release as well. + +## 2.8.0 (June 10, 2020) + +FEATURES: + +- `provider`: Add support for `DD_API_KEY`, `DD_APP_KEY` and `DD_HOST` env variables ([#469](https://github.com/DataDog/terraform-provider-datadog/issues/469)) +- `datadog_logs_custom_pipeline`: Add support for lookup processor ([#415](https://github.com/DataDog/terraform-provider-datadog/issues/415)) +- `datadog_integration_aws_lambda_arn`: Add AWS Log Lambda Integration ([#436](https://github.com/DataDog/terraform-provider-datadog/issues/436)) +- `datadog_integration_aws_log_collection`: Add AWS Log collection service resource ([#437](https://github.com/DataDog/terraform-provider-datadog/issues/437)) Thanks [@mhaley-miovision](https://github.com/mhaley-miovision) +- `datadog_dashboard`: Add support for tags_execution ([#524](https://github.com/DataDog/terraform-provider-datadog/issues/524)) +- `datadog_dashboard`: Add `legend_size` to api request ([#421](https://github.com/DataDog/terraform-provider-datadog/issues/421)) +- `provider`: Add "validate" option that can disable validation ([#474](https://github.com/DataDog/terraform-provider-datadog/issues/474)) Thanks [@bendrucker](https://github.com/bendrucker) + +IMPROVEMENTS: + +- `provider`: Harmonized errors across all resources ([#450](https://github.com/DataDog/terraform-provider-datadog/issues/450)) +- `provider`: Add more infos in user agent header ([#455](https://github.com/DataDog/terraform-provider-datadog/issues/455)) +- `provider`: Update the api error message ([#472](https://github.com/DataDog/terraform-provider-datadog/issues/472)) +- `datadog_screenboard`, `datadog_timeboard`: Add deprecation messages ([#496](https://github.com/DataDog/terraform-provider-datadog/issues/496)) +- `provider`: New UserAgent Header ([#455](https://github.com/DataDog/terraform-provider-datadog/issues/455)), ([#510](https://github.com/DataDog/terraform-provider-datadog/issues/510)), ([#511](https://github.com/DataDog/terraform-provider-datadog/issues/511)), and ([#512](https://github.com/DataDog/terraform-provider-datadog/issues/512)) +- `datadog_integration_aws`: Add full AWS Update support ([#521](https://github.com/DataDog/terraform-provider-datadog/issues/521)) + +BUGFIXES: + +- `datadog_logs_index`: Fail fast if index isn't imported ([#452](https://github.com/DataDog/terraform-provider-datadog/issues/452)) +- `datadog_integration_aws`: Do not set empty structures in request to create aws integration ([#505](https://github.com/DataDog/terraform-provider-datadog/issues/505)) Thanks [@miguelaferreira](https://github.com/miguelaferreira) +- `datadog_dashboard`: Add default to deprecated `count` field to avoid sending 0 ([#514](https://github.com/DataDog/terraform-provider-datadog/issues/514)) +- `datadog_integration_pagerduty`: Fix perpetual diff in api_token ([#518](https://github.com/DataDog/terraform-provider-datadog/issues/518)) Thanks [@bendrucker](https://github.com/bendrucker) +- `datadog_dashboard`: Add column revamp properties to dashboard log stream widget ([#517](https://github.com/DataDog/terraform-provider-datadog/issues/517)) + +NOTES: + +- This release replaces the underlying community driven Datadog API Go client [go-datadog-api](https://github.com/zorkian/go-datadog-api) with the Datadog Official API Go client [datadog-api-client-go](https://github.com/DataDog/datadog-api-client-go) for all resources listed below: + - `provider`: Add Datadog Go client API ([#477](https://github.com/DataDog/terraform-provider-datadog/issues/477)) and ([#456](https://github.com/DataDog/terraform-provider-datadog/issues/456)) + - `datadog_service_level_objective`: Migrate SLO resource with Datadog Go Client ([#490](https://github.com/DataDog/terraform-provider-datadog/issues/490)) + - `datadog_metric_metadata`: Migrate metric_metadata resource to use Datadog Go client ([#486](https://github.com/DataDog/terraform-provider-datadog/issues/486)) + - `datadog_integration_aws`: Migrate AWS resource to use Datadog Go client ([#481](https://github.com/DataDog/terraform-provider-datadog/issues/481)) + - `datadog_integration_gcp`: Migrate GCP resource to use Datadog Go client ([#482](https://github.com/DataDog/terraform-provider-datadog/issues/482)) + - `datadog_downtime`: Migrate Downtime resource to use Datadog Go client ([#480](https://github.com/DataDog/terraform-provider-datadog/issues/480)) + - `datadog_ip_ranges`: Migrate IP Range resource with Datadog Go client ([#491](https://github.com/DataDog/terraform-provider-datadog/issues/491)) + - `datadog_integration_pagerduty_service_object`: Migrate pagerduty_service_object resource to use Datadog Go client ([#488](https://github.com/DataDog/terraform-provider-datadog/issues/488)) + - `datadog_logs_index`, `datadog_logs_index_order`, `datadog_logs_integration_pipeline`, `datadog_logs_pipeline_order`: Migrate Logs resources to use Datadog Go client ([#483](https://github.com/DataDog/terraform-provider-datadog/issues/483)) + - `datadog_monitor`: Migrate monitor resource to use Datadog Go client ([#485](https://github.com/DataDog/terraform-provider-datadog/issues/485)) + - `datadog_dashboard_list`: Migrate Dashboard_list resource to use Datadog Go client ([#479](https://github.com/DataDog/terraform-provider-datadog/issues/479)) + - `datadog_integration_aws_log_collection`: Migrate aws_log_collection resource to use Datadog Go client ([#501](https://github.com/DataDog/terraform-provider-datadog/issues/501)) + - `datadog_logs_custom_pipeline`: Migrate Logs custom pipeline resource to utilize Datadog Go client ([#495](https://github.com/DataDog/terraform-provider-datadog/issues/495)) + - `datadog_synthetics_test`: Migrate synthetics resource to utilize Datadog Go Client ([#499](https://github.com/DataDog/terraform-provider-datadog/issues/499)) + - `datadog_integration_aws_log_collection`, `datadog_integration_aws_lambda_arn`: Migrate AWS logs to use the Datadog Go Client ([#497](https://github.com/DataDog/terraform-provider-datadog/issues/497)) + - `datadog_dashboard`: Migrate dashboard resource to use Datadog Go client ([#489](https://github.com/DataDog/terraform-provider-datadog/issues/489)) +- `datadog_screenboard` and `datadog_timeboard` resources are deprecated and should be converted to `datadog_dashboard` resources. +- Thanks [@NeverTwice](https://github.com/NeverTwice) ([#460](https://github.com/DataDog/terraform-provider-datadog/pull/460)) and [@sepulworld](https://github.com/sepulworld) ([#506](https://github.com/DataDog/terraform-provider-datadog/pull/506)) who contributed to this release as well. + +## 2.7.0 (February 10, 2020) + +IMPROVEMENTS: + +- `datadog_dashboard`: Add `template_variable_presets` parameter ([#401](https://github.com/DataDog/terraform-provider-datadog/issues/401)) +- `datadog_dashboard`: Add new Monitor Summary widget parameters: `summary_type` and `show_last_triggered` ([#396](https://github.com/DataDog/terraform-provider-datadog/issues/396)) +- `datadog_dashboard`: Hide deprecated Monitor Summary widget parameters: `count` and `start` ([#403](https://github.com/DataDog/terraform-provider-datadog/issues/403)) +- `datadog_monitor`: Improve monitor example with ignoring changes on silenced ([#406](https://github.com/DataDog/terraform-provider-datadog/issues/406)) +- `datadog_service_level_objective`: Fix optional threshold fields handling when updating ([#400](https://github.com/DataDog/terraform-provider-datadog/issues/400)) + +BUGFIXES: + +- `datadog_downtime`: Gracefully handle recreating downtimes that were canceled manually ([#405](https://github.com/DataDog/terraform-provider-datadog/issues/405)) +- `datadog_screenboard`: Properly set screenboard attributes from client response to not produce non-empty plans ([#404](https://github.com/DataDog/terraform-provider-datadog/issues/404)) + +NOTES: + +- This is the first release to use the new `terraform-plugin-sdk` ([#346](https://github.com/DataDog/terraform-provider-datadog/issues/346)) + +## 2.6.0 (January 21, 2020) + +FEATURES: + +- `datadog_dashboard`: Add Datadog dashboard SLO widget support ([#355](https://github.com/DataDog/terraform-provider-datadog/issues/355)) Thanks [@mbarrien](https://github.com/mbarrien) + +IMPROVEMENTS: + +- `datadog_logs_custom_pipeline`: Support all processors in Logs pipeline ([#357](https://github.com/DataDog/terraform-provider-datadog/pull/357)) Thanks [@tt810](https://github.com/tt810) + +BUGFIXES: + +- `datadog_service_level_objective`: Fix slo threshold warning value modified when storing the state ([#352](https://github.com/DataDog/terraform-provider-datadog/pull/352)) +- `datadog_service_level_objective`: `monitor_search` schema removed from the SLO resource as it is not yet supported ([#358](https://github.com/DataDog/terraform-provider-datadog/issues/358)) Thanks [@unclebconnor](https://github.com/unclebconnor) +- `datadog_monitor`: Resolve non empty diff: "no_data_timeframe = 0 -> 10" on plan diff ([#384](https://github.com/DataDog/terraform-provider-datadog/issues/384)) Thanks [@abicky](https://github.com/abicky) + +## 2.5.0 (October 22, 2019) + +FEATURES: + +- `datadog_ip_ranges`: New data source for IP ranges ([#298](https://github.com/DataDog/terraform-provider-datadog/issues/298)) +- `datadog_logs_custom_pipeline`: New resource for custom logs pipelines ([#312](https://github.com/DataDog/terraform-provider-datadog/issues/312), [#332](https://github.com/DataDog/terraform-provider-datadog/issues/332)) +- `datadog_logs_index`: New resource for logs indexes ([#326](https://github.com/DataDog/terraform-provider-datadog/issues/326)) +- `datadog_logs_index_order`: New resource for logs index ordering ([#326](https://github.com/DataDog/terraform-provider-datadog/issues/326)) +- `datadog_logs_integration_pipeline`: New resource for integration logs pipelines ([#312](https://github.com/DataDog/terraform-provider-datadog/issues/312), [#332](https://github.com/DataDog/terraform-provider-datadog/issues/332)) +- `datadog_logs_pipeline_order`: New resources for logs pipeline ordering ([#312](https://github.com/DataDog/terraform-provider-datadog/issues/312)) + +IMPROVEMENTS: + +- `datadog_dashboard`: Added documentation of `event` and `axis` ([#314](https://github.com/DataDog/terraform-provider-datadog/issues/314)) +- `datadog_screenboard`: Added `count` as a valid aggregation method ([#333](https://github.com/DataDog/terraform-provider-datadog/issues/333)) + +BUGFIXES: + +- `datadog_dashboard`: Fixed parsing of `compute.interval` and `group_by.sort.facet`, mark `group_by.facet` as optional for apm and log queries ([#322](https://github.com/DataDog/terraform-provider-datadog/issues/322), [#325](https://github.com/DataDog/terraform-provider-datadog/issues/325)) +- `datadog_dashboard`: Properly respect `show_legend` ([#329](https://github.com/DataDog/terraform-provider-datadog/issues/329)) +- `datadog_integration_pagerduty`: Add missing exists methods to prevent failing when resource was manually removed outside of Terraform ([#324](https://github.com/DataDog/terraform-provider-datadog/issues/324)) +- `datadog_integration_pagerduty_service_object`: Add missing exists methods to prevent failing when resource was manually removed outside of Terraform ([#324](https://github.com/DataDog/terraform-provider-datadog/issues/324)) + +## 2.4.0 (September 11, 2019) + +FEATURES: + +- `datadog_dashboard_list`: New resource for dashboard lists ([#296](https://github.com/DataDog/terraform-provider-datadog/issues/296)) + +IMPROVEMENTS: + +- `datadog_dashboard`: Allow specifying `event` and `yaxis` for timeseries definitions ([#282](https://github.com/DataDog/terraform-provider-datadog/issues/282)) + +## 2.3.0 (August 29, 2019) + +IMPROVEMENTS: + +- `datadog-dashboards`: Add resources for log, apm and process query in legacy dashboards ([#272](https://github.com/DataDog/terraform-provider-datadog/issues/272)) + +BUGFIXES: + +- `datadog_integration_pagerduty`: Make sure PD services don't get removed by updating PD resource ([#304](https://github.com/DataDog/terraform-provider-datadog/issues/304)) + +## 2.2.0 (August 19, 2019) + +FEATURES: + +- `datadog_service_level_objective`: New resource for Service Level Objective (SLO) ([#263](https://github.com/DataDog/terraform-provider-datadog/issues/263)) + +IMPROVEMENTS: + +- `datadog_dashbaord`: Add support for style block in dashboard widgets. ([#277](https://github.com/DataDog/terraform-provider-datadog/issues/277)) +- `datadog_dashboard`: Add support for metadata block in dashboard widgets ([#278](https://github.com/DataDog/terraform-provider-datadog/issues/278)) +- `datadog_synthetics_test`: Support SSL synthetics tests. ([#279](https://github.com/DataDog/terraform-provider-datadog/issues/279)) + +BUGFIXES: + +- `datadog_dashboards`: Safely type assert optional fields from log and apm query to avoid a panic if they aren't supplied ([#283](https://github.com/DataDog/terraform-provider-datadog/issues/283)) +- `datadog_synthetics_test`: Fix follow redirects field to properly apply and save in state. ([#256](https://github.com/DataDog/terraform-provider-datadog/issues/256)) + +## 2.1.0 (July 24, 2019) + +FEATURES: + +- `datadog_dashboard`: New Resource combining screenboard and timeboard, allowing a single config to manage all of your Datadog Dashboards. ([#249](https://github.com/DataDog/terraform-provider-datadog/issues/249)) +- `datadog_integration_pagerduty_service_object`: New Resource that allows the configuration of individual pagerduty services for the Datadog Pagerduty Integration. ([#237](https://github.com/DataDog/terraform-provider-datadog/issues/237)) + +IMPROVEMENTS: + +- `datadog_aws`: Add a mutex around all API operations for this resource. ([#254](https://github.com/DataDog/terraform-provider-datadog/issues/254)) +- `datadog_downtime`: General improvements around allowing the resource to be ran multiple times without sending any unchanged values for the start/end times. Also fixes non empty diff when monitor_tags isn't set. ([#264](https://github.com/DataDog/terraform-provider-datadog/issues/264)] [[#267](https://github.com/DataDog/terraform-provider-datadog/issues/267)) +- `datadog_monitor`: Only add a threshold window if a recovery or trigger window is set. [[#260](https://github.com/DataDog/terraform-provider-datadog/issues/260)] Thanks [@heldersepu](https://github.com/heldersepu) +- `datadog_user`: Make `is_admin` computed to continue its deprecation path and avoid spurious diffs. ([#251](https://github.com/DataDog/terraform-provider-datadog/issues/251)) + +NOTES: + +- This release includes Terraform SDK upgrade to 0.12.5. ([#265](https://github.com/DataDog/terraform-provider-datadog/issues/265)) + +## 2.0.2 (June 26, 2019) + +BUGFIXES: + +- `datadog_monitor`: DiffSuppress the difference between `metric alert` and `query alert` no matter what is in the current state and prevent the force recreation of monitors due to this change. ([#247](https://github.com/DataDog/terraform-provider-datadog/issues/247)) + +## 2.0.1 (June 21, 2019) + +BUGFIXES: + +- `datadog_monitor`: Don't force the destruction and recreation of a monitor when the type changes between `metric alert` and `query alert`. ([#242](https://github.com/DataDog/terraform-provider-datadog/issues/242)) + +## 2.0.0 (June 18, 2019) + +NOTES: + +- `datadog_monitor`: The silence attribute is beginning its deprecation process, please use `datadog_downtime` instead ([#221](https://github.com/DataDog/terraform-provider-datadog/issues/221)) + +IMPROVEMENTS: + +- `datadog_monitor`: Use ForceNew when changing the Monitor type ([#236](https://github.com/DataDog/terraform-provider-datadog/issues/236)) +- `datadog_monitor`: Add default to `no data` timeframe of 10 minutes. ([#212](https://github.com/DataDog/terraform-provider-datadog/issues/212)) +- `datadog_synthetics_test`: Support synthetics monitors in composite monitors. ([#222](https://github.com/DataDog/terraform-provider-datadog/issues/222)) +- `datadog_downtime`: Add validation to tags, add timezone parameter, improve downtime id handling, add descriptions to fields. ([#204](https://github.com/DataDog/terraform-provider-datadog/issues/204)) +- `datadog_screenboard`: Add support for metadata alias in graphs. ([#215](https://github.com/DataDog/terraform-provider-datadog/issues/215)) +- `datadog_screenboard`: Add `custom_bg_color` to graph config. [[#189](https://github.com/DataDog/terraform-provider-datadog/issues/189)] Thanks [@milanvdm](https://github.com/milanvdm) +- Update the vendored go client to `v2.21.0`. ([#230](https://github.com/DataDog/terraform-provider-datadog/issues/230)) + +BUGFIXES: + +- `datadog_timeboard`: Fix the `extra_col` from having a non empty plan when there are no changes. ([#231](https://github.com/DataDog/terraform-provider-datadog/issues/231)) +- `datadog_timeboard`: Fix the `precision` from having a non empty plan when there are no changes. ([#228](https://github.com/DataDog/terraform-provider-datadog/issues/228)) +- `datadog_monitor`: Fix the sorting of monitor tags that could lead to a non empty diff. ([#214](https://github.com/DataDog/terraform-provider-datadog/issues/214)) +- `datadog_monitor`: Properly save `query_config` as to avoid to an improper non empty diff. ([#209](https://github.com/DataDog/terraform-provider-datadog/issues/209)) +- `datadog_monitor`: Fix and clarify documentation on unmuting monitor scopes. ([#202](https://github.com/DataDog/terraform-provider-datadog/issues/202)) +- `datadog_screenboard`: Change monitor schema to be of type String instead of Int. [[#154](https://github.com/DataDog/terraform-provider-datadog/issues/154)] Thanks [@mnaboka](https://github.com/mnaboka) + +## 1.9.0 (May 09, 2019) + +IMPROVEMENTS: + +- `datadog_downtime`: Add `monitor_tags` getting and setting ([#167](https://github.com/DataDog/terraform-provider-datadog/issues/167)) +- `datadog_monitor`: Add support for `enable_logs` in log monitors ([#151](https://github.com/DataDog/terraform-provider-datadog/issues/151)) +- `datadog_monitor`: Add suport for `threshold_windows` attribute ([#131](https://github.com/DataDog/terraform-provider-datadog/issues/131)) +- Support importing dashboards using the new string ID ([#184](https://github.com/DataDog/terraform-provider-datadog/issues/184)) +- Various documentation fixes and improvements ([#152](https://github.com/DataDog/terraform-provider-datadog/issues/152), [#171](https://github.com/DataDog/terraform-provider-datadog/issues/171), [#176](https://github.com/DataDog/terraform-provider-datadog/issues/176), [#178](https://github.com/DataDog/terraform-provider-datadog/issues/178), [#180](https://github.com/DataDog/terraform-provider-datadog/issues/180), [#183](https://github.com/DataDog/terraform-provider-datadog/issues/183)) + +NOTES: + +- This release includes Terraform SDK upgrade to 0.12.0-rc1. The provider is backwards compatible with Terraform v0.11.X, there should be no significant changes in behavior. Please report any issues to either [Terraform issue tracker](https://github.com/hashicorp/terraform/issues) or to [Terraform Datadog Provider issue tracker](https://github.com/DataDog/terraform-provider-datadog/issues) ([#194](https://github.com/DataDog/terraform-provider-datadog/issues/194), [#198](https://github.com/DataDog/terraform-provider-datadog/issues/198)) + +## 1.8.0 (April 15, 2019) + +INTERNAL: + +- provider: Enable request/response logging in `>=DEBUG` mode ([#153](https://github.com/DataDog/terraform-provider-datadog/issues/153)) + +IMPROVEMENTS: + +- Add Synthetics API and Browser tests support + update go-datadog-api to latest. ([169](https://github.com/DataDog/terraform-provider-datadog/pull/169)) + +## 1.7.0 (March 05, 2019) + +BUGFIXES: + +- Bump go api client to 2.19.0 to fix TileDefStyle.fillMax type errors. ([143](https://github.com/DataDog/terraform-provider-datadog/pull/143))([144](https://github.com/DataDog/terraform-provider-datadog/pull/144)) +- Fix the usage of `start_date` and `end_data` only being read on the first apply. ([145](https://github.com/DataDog/terraform-provider-datadog/pull/145)) + +IMPROVEMENTS: + +- Upgrade to Go 1.11. ([141](https://github.com/DataDog/terraform-provider-datadog/pull/141/files)) +- Add AWS Integration resource to the docs. ([146](https://github.com/DataDog/terraform-provider-datadog/pull/146)) + +FEATURES: + +- **New Resource:** `datadog_integration_pagerduty` ([135](https://github.com/DataDog/terraform-provider-datadog/pull/135)) + +## 1.6.0 (November 30, 2018) + +BUGFIXES: + +- the graph.style.palette_flip field is a boolean but only works if it's passed as a string. ([#29](https://github.com/DataDog/terraform-provider-datadog/issues/29)) +- datadog_monitor - Removal of 'silenced' resource argument has no practical effect. ([#41](https://github.com/DataDog/terraform-provider-datadog/issues/41)) +- datadog_screenboard - widget swapping `x` and `y` parameters. ([#119](https://github.com/DataDog/terraform-provider-datadog/issues/119)) +- datadog_screenboard - panic: interface conversion: interface {} is string, not float64. ([#117](https://github.com/DataDog/terraform-provider-datadog/issues/117)) + +IMPROVEMENTS: + +- Feature Request: AWS Integration. ([#76](https://github.com/DataDog/terraform-provider-datadog/issues/76)) +- Bump datadog api to v2.18.0 and add support for include units and zero. ([#121](https://github.com/DataDog/terraform-provider-datadog/pull/121)) + +## 1.5.0 (November 06, 2018) + +IMPROVEMENTS: + +- Add Google Cloud Platform integration ([#108](https://github.com/DataDog/terraform-provider-datadog/pull/108)) +- Add new hostmap widget options: `node type`, `fill_min` and `fill_max`. ([#106](https://github.com/DataDog/terraform-provider-datadog/pull/106)) +- Use dates to set downtime interval, improve docs. ([#113](https://github.com/DataDog/terraform-provider-datadog/pull/113)) +- Bump Terraform provider SDK to latest. ([#110](https://github.com/DataDog/terraform-provider-datadog/pull/110)) +- Better document `evaluation_delay` option. ([#112](https://github.com/DataDog/terraform-provider-datadog/pull/112)) + +## 1.4.0 (October 02, 2018) + +IMPROVEMENTS: + +- Pull changes from go-datadog-api v2.14.0 ([#99](https://github.com/DataDog/terraform-provider-datadog/pull/99)) +- Add `api_url` argument to the provider ([#101](https://github.com/DataDog/terraform-provider-datadog/pull/101)) + +BUGFIXES: + +- Allow `new_host_delay` to be unset ([#100](https://github.com/DataDog/terraform-provider-datadog/issues/100)) + +## 1.3.0 (September 25, 2018) + +IMPROVEMENTS: + +- Add full support for Datadog screenboards ([#91](https://github.com/DataDog/terraform-provider-datadog/pull/91)) + +BUGFIXES: + +- Do not compute `new_host_delay` ([#88](https://github.com/DataDog/terraform-provider-datadog/pull/88)) +- Remove buggy uptime widget ([#93](https://github.com/DataDog/terraform-provider-datadog/pull/93)) + +## 1.2.0 (August 27, 2018) + +BUG FIXES: + +- Update "monitor type" options in docs ([#81](https://github.com/DataDog/terraform-provider-datadog/pull/81)) +- Fix typo in timeboard documentation ([#83](https://github.com/DataDog/terraform-provider-datadog/pull/83)) + +IMPROVEMENTS: + +- Update `go-datadog-api` to v.2.11.0 and move vendoring from `gopkg.in/zorkian/go-datadog-api.v2` to `github.com/zorkian/go-datadog-api` ([#84](https://github.com/DataDog/terraform-provider-datadog/pull/84)) +- Deprecate `is_admin` as part of the work needed to add support for `access_role` ([#85](https://github.com/DataDog/terraform-provider-datadog/pull/85)) + +## 1.1.0 (July 30, 2018) + +IMPROVEMENTS: + +- Added more docs detailing expected weird behaviours from the Datadog API. ([#79](https://github.com/DataDog/terraform-provider-datadog/pull/79)) +- Added support for 'unknown' monitor threshold field. ([#45](https://github.com/DataDog/terraform-provider-datadog/pull/45)) +- Deprecated the `role` argument for `User` resources since it's now a noop on the Datadog API. ([#80](https://github.com/DataDog/terraform-provider-datadog/pull/80)) + +## 1.0.4 (July 06, 2018) + +BUG FIXES: + +- Bump `go-datadog-api.v2` to v2.10.0 thus fixing tag removal on monitor updates ([#43](https://github.com/DataDog/terraform-provider-datadog/issues/43)) + +## 1.0.3 (January 03, 2018) + +IMPROVEMENTS: + +- `datadog_downtime`: adding support for setting `monitor_id` ([#18](https://github.com/DataDog/terraform-provider-datadog/issues/18)) + +## 1.0.2 (December 19, 2017) + +IMPROVEMENTS: + +- `datadog_monitor`: Add support for monitor recovery thresholds ([#37](https://github.com/DataDog/terraform-provider-datadog/issues/37)) + +BUG FIXES: + +- Fix issue with DataDog service converting metric alerts to query alerts ([#16](https://github.com/DataDog/terraform-provider-datadog/issues/16)) + +## 1.0.1 (December 06, 2017) + +BUG FIXES: + +- Fix issue reading resources that have been updated outside of Terraform ([#34](https://github.com/DataDog/terraform-provider-datadog/issues/34)) + +## 1.0.0 (October 20, 2017) + +BUG FIXES: + +- Improved detection of "drift" when graphs are reconfigured outside of Terraform. ([#27](https://github.com/DataDog/terraform-provider-datadog/issues/27)) +- Fixed API response decoding error on graphs. ([#27](https://github.com/DataDog/terraform-provider-datadog/issues/27)) + +## 0.1.1 (September 26, 2017) + +FEATURES: + +- **New Resource:** `datadog_metric_metadata` ([#17](https://github.com/DataDog/terraform-provider-datadog/issues/17)) + +## 0.1.0 (June 20, 2017) + +NOTES: + +- Same functionality as that of Terraform 0.9.8. Repacked as part of [Provider Splitout](https://www.hashicorp.com/blog/upcoming-provider-changes-in-terraform-0-10/) diff --git a/.terraform/providers/registry.terraform.io/datadog/datadog/3.1.2/darwin_amd64/LICENSE b/.terraform/providers/registry.terraform.io/datadog/datadog/3.1.2/darwin_amd64/LICENSE new file mode 100755 index 0000000..a612ad9 --- /dev/null +++ b/.terraform/providers/registry.terraform.io/datadog/datadog/3.1.2/darwin_amd64/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/.terraform/providers/registry.terraform.io/datadog/datadog/3.1.2/darwin_amd64/LICENSE-3rdparty.csv b/.terraform/providers/registry.terraform.io/datadog/datadog/3.1.2/darwin_amd64/LICENSE-3rdparty.csv new file mode 100755 index 0000000..cd1f457 --- /dev/null +++ b/.terraform/providers/registry.terraform.io/datadog/datadog/3.1.2/darwin_amd64/LICENSE-3rdparty.csv @@ -0,0 +1,200 @@ +Component,Origin,License,Copyright +go.sum,cloud.google.com/go,Apache-2.0,2014 Google LLC +go.sum,cloud.google.com/go/bigquery,Apache-2.0,2014 Google LLC +go.sum,cloud.google.com/go/datastore,Apache-2.0,2014 Google LLC +go.sum,github.com/BurntSushi/toml,MIT,2013 TOML authors +go.sum,github.com/BurntSushi/xgb,BSD-3-Clause,2009 The XGB Authors +go.sum,github.com/DataDog/datadog-api-client-go,Apache-2.0,"2019-Present Datadog, Inc." +go.sum,github.com/DataDog/datadog-go,MIT,"2015 Datadog, Inc" +go.sum,github.com/DataDog/dd-trace-go,Apache-2.0 OR BSD-3-Clause,"2016-Present Datadog, Inc." +go.sum,github.com/agext/levenshtein,Apache-2.0,2016 ALRUX Inc. +go.sum,github.com/agl/ed25519,BSD-3-Clause,2012 The Go Authors +go.sum,github.com/apparentlymart/go-cidr,MIT,2015 Martin Atkins +go.sum,github.com/apparentlymart/go-dump,MPL-2.0, +go.sum,github.com/apparentlymart/go-textseg,MIT and Apache-2.0 and Unicode-DFS-2016,2017 Martin Atkins and 2014 Couchbase Inc. and 2016 Unicode Inc +go.sum,github.com/armon/go-radix,MIT,2014 Armon Dadgar +go.sum,github.com/aslakhellesoy/gox,MPL-2.0, +go.sum,github.com/aws/aws-sdk-go,Apache-2.0,2014-2015 Stripe Inc. and 2015 Amazon.com Inc. +go.sum,github.com/bgentry/go-netrc,MIT,2010 Fazlul Shahriar and 2014 Blake Gentry +go.sum,github.com/bgentry/speakeasy,MIT,2017 Blake Gentry +go.sum,github.com/cenkalti/backoff,MIT,2014 Cenk Altı +go.sum,github.com/census-instrumentation/opencensus-proto,Apache-2.0,"2019, OpenCensus Authors" +go.sum,github.com/cheggaaa/pb,BSD-3-Clause,2012-2015 Sergey Cherepanov +go.sum,github.com/client9/misspell,MIT,2015-2017 Nick Galbreath +go.sum,github.com/creack/pty,MIT,2011 Keith Rarick +go.sum,github.com/cucumber/gherkin-go/v13,MIT,Cucumber Ltd and Gaspar Nagy and Björn Rasmusson and Peter Sergeant +go.sum,github.com/cucumber/messages-go/v12,MIT,Cucumber Ltd +go.sum,github.com/davecgh/go-spew,ISC,2012-2016 Dave Collins +go.sum,github.com/dnaeon/go-vcr,BSD-2-Clause,2015-2016 Marin Atanasov Nikolov +go.sum,github.com/envoyproxy/go-control-plane,Apache-2.0,2018 Envoyproxy Authors +go.sum,github.com/envoyproxy/protoc-gen-validate,Apache-2.0,2019 Envoy Project Authors +go.sum,github.com/fatih/color,MIT,2013 Fatih Arslan +go.sum,github.com/go-bdd/assert,MIT,2020 GoBDD +go.sum,github.com/go-bdd/gobdd,MIT,2019 Bartłomiej Klimczak +go.sum,github.com/go-test/deep,MIT,2015-2017 Daniel Nichter +go.sum,github.com/gofrs/uuid,MIT,2013-2018 by Maxim Bublis +go.sum,github.com/gogo/protobuf,BSD-3-Clause,2010 The Go Authors and 2013 The GoGo Authors +go.sum,github.com/golang/glog,Apache-2.0,2013 Google Inc. +go.sum,github.com/golang/mock,Apache-2.0,2020 Google Inc. +go.sum,github.com/golang/protobuf,BSD-3-Clause,2010 The Go Authors +go.sum,github.com/golang/snappy,BSD-3-Clause,2011 The Snappy-Go Authors +go.sum,github.com/google/btree,Apache-2.0,2014 Google Inc. +go.sum,github.com/google/go-cmp,BSD-3-Clause,2017 The Go Authors +go.sum,github.com/google/martian,Apache-2.0,2015 Google Inc. +go.sum,github.com/google/pprof,Apache-2.0,2014 Google Inc. +go.sum,github.com/google/uuid,BSD-3-Clause,2009-2014 Google Inc. +go.sum,github.com/googleapis/gax-go/v2,BSD-3-Clause,2016 Google Inc. +go.sum,github.com/h2non/parth,MIT,2018 codemodus +go.sum,github.com/hashicorp/errwrap,MPL-2.0, +go.sum,github.com/hashicorp/go-cleanhttp,MPL-2.0, +go.sum,github.com/hashicorp/go-getter,MPL-2.0, +go.sum,github.com/hashicorp/go-hclog,MIT,2017 HashiCorp +go.sum,github.com/hashicorp/go-multierror,MPL-2.0, +go.sum,github.com/hashicorp/go-plugin,MPL-2.0, +go.sum,github.com/hashicorp/go-safetemp,MPL-2.0, +go.sum,github.com/hashicorp/go-uuid,MPL-2.0, +go.sum,github.com/hashicorp/go-version,MPL-2.0, +go.sum,github.com/hashicorp/golang-lru,MPL-2.0, +go.sum,github.com/hashicorp/hcl,MPL-2.0, +go.sum,github.com/hashicorp/hcl/v2,MPL-2.0, +go.sum,github.com/hashicorp/logutils,MPL-2.0, +go.sum,github.com/hashicorp/terraform-config-inspect,MPL-2.0, +go.sum,github.com/hashicorp/terraform-json,MPL-2.0, +go.sum,github.com/hashicorp/terraform-plugin-sdk,MPL-2.0, +go.sum,github.com/hashicorp/terraform-plugin-test,MPL-2.0, +go.sum,github.com/hashicorp/terraform-svchost,MPL-2.0, +go.sum,github.com/hashicorp/yamux,MPL-2.0, +go.sum,github.com/jmespath/go-jmespath,Apache-2.0,2015 James Saryerwinnie +go.sum,github.com/jonboulle/clockwork,Apache-2.0, +go.sum,github.com/jstemmer/go-junit-report,MIT,2012 Joel Stemmer +go.sum,github.com/keybase/go-crypto,BSD-3-Clause,2009 The Go Authors +go.sum,github.com/kisielk/errcheck,MIT,2013 Kamil Kisiel +go.sum,github.com/kisielk/gotool,MIT,2013 Kamil Kisiel +go.sum,github.com/kr/pretty,MIT,2012 Keith Rarick +go.sum,github.com/kr/pty,MIT,2019 Keith Rarick +go.sum,github.com/kr/text,MIT,2012 Keith Rarick +go.sum,github.com/kylelemons/godebug,Apache-2.0,2013 Google Inc +go.sum,github.com/mattn/go-colorable,MIT,2016 Yasuhiro Matsumoto +go.sum,github.com/mattn/go-isatty,MIT,Yasuhiro MATSUMOTO +go.sum,github.com/mattn/go-runewidth,MIT,2016 Yasuhiro Matsumoto +go.sum,github.com/mcuadros/go-lookup,MIT,2015 Máximo Cuadros +go.sum,github.com/mitchellh/cli,MPL-2.0, +go.sum,github.com/mitchellh/colorstring,MIT,2014 Mitchell Hashimoto +go.sum,github.com/mitchellh/copystructure,MIT,2014 Mitchell Hashimoto +go.sum,github.com/mitchellh/go-homedir,MIT,2013 Mitchell Hashimoto +go.sum,github.com/mitchellh/go-testing-interface,MIT,2016 Mitchell Hashimoto +go.sum,github.com/mitchellh/go-wordwrap,MIT,2014 Mitchell Hashimoto +go.sum,github.com/mitchellh/iochan,MIT,2015 Mitchell Hashimoto +go.sum,github.com/mitchellh/mapstructure,MIT,2013 Mitchell Hashimoto +go.sum,github.com/mitchellh/reflectwalk,MIT,2013 Mitchell Hashimoto +go.sum,github.com/nbio/st,Apache-2.0,2014 nb.io LLC +go.sum,github.com/niemeyer/pretty,MIT,2012 Keith Rarick +go.sum,github.com/oklog/run,Apache-2.0, +go.sum,github.com/opentracing/opentracing-go,Apache-2.0, +go.sum,github.com/philhofer/fwd,MIT,2014-2015 Philip Hofer +go.sum,github.com/pierrec/lz4,BSD-3-Clause,2015 Pierre Curto +go.sum,github.com/pkg/errors,BSD-2-Clause,2015 Dave Cheney +go.sum,github.com/pmezard/go-difflib,BSD-3-Clause,2013 Patrick Mezard +go.sum,github.com/posener/complete,MIT,2017 Eyal Posener +go.sum,github.com/prometheus/client_model,Apache-2.0,2012-2015 The Prometheus Authors +go.sum,github.com/sergi/go-diff,MIT,2012-2016 The go-diff Authors +go.sum,github.com/spf13/afero,Apache-2.0,2009 The Go Authors and 2014 Steve Francia +go.sum,github.com/spf13/pflag,BSD-3-Clause,2012 The Go Authors and 2012 Alex Ogier +go.sum,github.com/stretchr/objx,MIT,2014 Stretchr Inc. and 2017-2018 objx contributors +go.sum,github.com/stretchr/testify,MIT,2012-2020 Mat Ryer and Tyler Bunnell and contributors. +go.sum,github.com/tinylib/msgp,MIT,2014 Philip Hofer +go.sum,github.com/ulikunitz/xz,MIT,2014-2020 Ulrich Kunitz +go.sum,github.com/vmihailenco/msgpack,BSD-2-Clause,2013 The github.com/vmihailenco/msgpack Authors +go.sum,github.com/zclconf/go-cty,MIT,2017-2018 Martin Atkins +go.sum,github.com/zclconf/go-cty-yaml,Apache-2.0,2011-2016 Canonical Ltd and 2019 Martin Atkins +go.sum,github.com/zorkian/go-datadog-api,BSD-3-Clause,2013 by authors and contributors +go.sum,go.opencensus.io,Apache-2.0,"2018, OpenCensus Authors" +go.sum,golang.org/x/crypto,BSD-3-Clause,2009 The Go Authors +go.sum,golang.org/x/exp,BSD-3-Clause,2009 The Go Authors +go.sum,golang.org/x/image,BSD-3-Clause,2009 The Go Authors +go.sum,golang.org/x/lint,BSD-3-Clause,2013 The Go Authors +go.sum,golang.org/x/mobile,BSD-3-Clause,2009 The Go Authors +go.sum,golang.org/x/net,BSD-3-Clause,2009 The Go Authors +go.sum,golang.org/x/oauth2,BSD-3-Clause,2009 The Go Authors +go.sum,golang.org/x/sync,BSD-3-Clause,2009 The Go Authors +go.sum,golang.org/x/sys,BSD-3-Clause,2019 The Go Authors +go.sum,golang.org/x/text,BSD-3-Clause,2009 The Go Authors +go.sum,golang.org/x/time,BSD-3-Clause,2019 The Go Authors +go.sum,golang.org/x/tools,BSD-3-Clause,2019 The Go Authors +go.sum,golang.org/x/xerrors,BSD-3-Clause,2019 The Go Authors +go.sum,google.golang.org/api,BSD-3-Clause,2011 Google Inc +go.sum,google.golang.org/appengine,Apache-2.0,Google Inc. +go.sum,google.golang.org/genproto,Apache-2.0,2018 Google Inc. +go.sum,google.golang.org/grpc,Apache-2.0,2016 gRPC authors. +go.sum,gopkg.in/DataDog/dd-trace-go.v1,Apache-2.0,"2016-Present Datadog, Inc." +go.sum,gopkg.in/check.v1,BSD-2-Clause,2010-2013 Gustavo Niemeyer +go.sum,gopkg.in/cheggaaa/pb.v1,BSD-3-Clause,2012-2015 Sergey Cherepanov +go.sum,gopkg.in/h2non/gock.v1,MIT,2016-2019 Tomas Aparicio +go.sum,gopkg.in/yaml.v2,Apache-2.0,2011-2016 Canonical Ltd. +go.sum,gotest.tools,Apache-2.0,2018 gotest.tools authors +go.sum,honnef.co/go/tools,MIT,2016 Dominik Honnef +go.sum,rsc.io/binaryregexp,BSD-3-Clause,2009 The Go Authors +go.sum,cloud.google.com/go/pubsub,Apache-2.0,Copyright 2018 Google LLC +go.sum,cloud.google.com/go/storage,Apache-2.0,Copyright 2014 Google LLC +go.sum,dmitri.shuralyov.com/gpu/mtl,BSD-3-Clause,2018 The Go Authors. +go.sum,github.com/alcortesm/tgz,MIT,2016 Alberto Cortés +go.sum,github.com/anmitsu/go-shlex,MIT,anmitsu +go.sum,github.com/armon/go-socks5,MIT,2014 Armon Dadgar +go.sum,github.com/chzyer/logex,MIT,2015Chzyer +go.sum,github.com/chzyer/readline,MIT,2015 Chzyer +go.sum,github.com/chzyer/test,MIT,2016 Chzyer +go.sum,github.com/cncf/udpa/go,Apache-2.0,The Authors +go.sum,github.com/emirpasic/gods,BSD 2-Clause,"2015, Emir Pasic" +go.sum,github.com/flynn/go-shlex,Apache-2.0,2012 Google Inc. +go.sum,github.com/gliderlabs/ssh,BSD-3-Clause,2016 Glider Labs +go.sum,github.com/go-git/gcfg,BSD-3-Clause,2012 Péter Surányi. Portions Copyright (c) 2009 The Go +go.sum,github.com/go-git/go-billy/v5,Apache-2.0,The Authors +go.sum,github.com/go-git/go-git-fixtures/v4,Apache-2.0,The Authors +go.sum,github.com/go-git/go-git/v5,Apache-2.0,The Authors +go.sum,github.com/go-gl/glfw,BSD-3-Clause,2012 The glfw3-go Authors +go.sum,github.com/go-gl/glfw/v3.3/glfw,BSD-3-Clause,2012 The glfw3-go Authors +go.sum,github.com/golang/groupcache,Apache-2.0,2013 Google Inc. +go.sum,github.com/google/martian/v3,Apache-2.0,2015 Google Inc. +go.sum,github.com/google/renameio,Apache-2.0,2018 Google Inc. +go.sum,github.com/hashicorp/go-checkpoint,MPL-2.0, +go.sum,github.com/hashicorp/terraform-exec,MPL-2.0, +go.sum,github.com/hashicorp/terraform-plugin-test/v2,MPL-2.0, +go.sum,github.com/ianlancetaylor/demangle,BSD-3-Clause,2015 The Go Authors. +go.sum,github.com/imdario/mergo,BSD-3-Clause,2013 Dario Castañé. 2012 The Go Authors. +go.sum,github.com/jbenet/go-context,MIT,2014 Juan Batiz-Benet +go.sum,github.com/jessevdk/go-flags,BSD-3-Clause,2012 Jesse van den Kieboom. +go.sum,github.com/jhump/protoreflect,Apache-2.0,The Authors +go.sum,github.com/kevinburke/ssh_config,MIT,2017 Kevin Burke. +go.sum,github.com/rogpeppe/go-internal,BSD-3-Clause,2018 The Go Authors. +go.sum,github.com/therve/terraform-plugin-sdk,MPL-2.0, +go.sum,github.com/xanzy/ssh-agent,Apache-2.0,"2015, Sander van Harmelen" +go.sum,github.com/yuin/goldmark,MIT,2019 Yusuke Inuzuka +go.sum,golang.org/x/mod,BSD-3-Clause,2009 The Go Authors. +go.sum,google.golang.org/protobuf,BSD-3-Clause,2018 The Go Authors. +go.sum,gopkg.in/errgo.v2,BSD-3-Clause,"Copyright © 2013, Roger Peppe" +go.sum,gopkg.in/warnings.v0,BSD 2-Clause,2016 Péter Surányi. +go.sum,rsc.io/quote/v3,BSD-3-Clause,2009 The Go Authors. +go.sum,rsc.io/sampler,BSD-3-Clause,2009 The Go Authors. +go.sum,github.com/Masterminds/goutils,Apache-2.0,Copyright 2014 Alexander Okoli +go.sum,github.com/Masterminds/semver,MIT,"2014-2019, Matt Butcher and Matt Farina" +go.sum,github.com/Masterminds/sprig,MIT,2013-2020 Masterminds +go.sum,github.com/andybalholm/crlf,BSD-2-Clause,2015 Andy Balholm. +go.sum,github.com/apparentlymart/go-textseg/v12,MIT,2017 Martin Atkins +go.sum,github.com/hashicorp/terraform-plugin-docs,MPL-2.0, +go.sum,github.com/zippolyte/terraform-plugin-docs,MPL-2.0, +go.sum,github.com/huandu/xstrings,MIT,2015 Huan Du. +go.sum,github.com/russross/blackfriday,BSD-2-Clause,2011 Russ Ross +go.sum,github.com/vmihailenco/msgpack/v4,BSD-2-Clause,2013 The github.com/vmihailenco/msgpack Authors. +go.sum,github.com/vmihailenco/tagparser,BSD-2-Clause,2019 The github.com/vmihailenco/tagparser Authors. +go.sum,github.com/zclconf/go-cty-debug,MIT,2019 Martin Atkins +go.sum,gopkg.in/yaml.v3,MIT/Apache-2.0,2006-2010 Kirill Simonov 2011-2019 Canonical Ltd +go.sum,github.com/Microsoft/go-winio,MIT,2015 Microsoft +go.sum,github.com/konsorten/go-windows-terminal-sequences,MIT,2017 marvin + konsorten GmbH +go.sum,github.com/sirupsen/logrus,MIT,2014 Simon Eskildsen +go.sum,golang.org/x/term,BSD-3-Clause,2009 The Go Authors +go.sum,github.com/hashicorp/go-cty,MIT,Copyright (c) 2017-2018 Martin Atkins +go.sum,github.com/hashicorp/terraform-plugin-go,MPL-2.0, +go.sum,github.com/hashicorp/terraform-plugin-sdk/v2,MPL-2.0, +go.sum,github.com/nsf/jsondiff,MIT,Copyright (C) 2019 nsf +go.sum,github.com/apparentlymart/go-textseg/v13,MIT,Copyright (c) 2017-2018 Martin Atkins +go.sum,github.com/klauspost/compress,BSD-3-Clause,Copyright (c) 2019 Klaus Post diff --git a/.terraform/providers/registry.terraform.io/datadog/datadog/3.1.2/darwin_amd64/README.md b/.terraform/providers/registry.terraform.io/datadog/datadog/3.1.2/darwin_amd64/README.md new file mode 100755 index 0000000..f5c5092 --- /dev/null +++ b/.terraform/providers/registry.terraform.io/datadog/datadog/3.1.2/darwin_amd64/README.md @@ -0,0 +1,35 @@ +# Terraform Provider + +- Website: https://www.terraform.io +- [![Gitter chat](https://badges.gitter.im/hashicorp-terraform/Lobby.png)](https://gitter.im/hashicorp-terraform/Lobby) +- Mailing list: [Google Groups](http://groups.google.com/group/terraform-tool) + + + +## Requirements + +- [Terraform](https://www.terraform.io/downloads.html) 0.10.x + +## Building The Provider + +Clone repository to: `$GOPATH/src/github.com/DataDog/terraform-provider-datadog` + +```sh +$ mkdir -p $GOPATH/src/github.com/DataDog; cd $GOPATH/src/github.com/DataDog +$ git clone git@github.com:DataDog/terraform-provider-datadog +``` + +Enter the provider directory and build the provider + +```sh +$ cd $GOPATH/src/github.com/DataDog/terraform-provider-datadog +$ make build +``` + +**Note**: For contributions created from forks, the repository should still be cloned under the `$GOPATH/src/github.com/DataDog/terraform-provider-datadog` directory to allow the provided `make` commands to properly run, build, and test this project. + +## Using the provider + +If you're building the provider, follow the instructions to [install it as a plugin.](https://www.terraform.io/docs/plugins/basics.html#installing-a-plugin) After placing it into your plugins directory, run `terraform init` to initialize it. + +Further [usage documentation is available on the Terraform website](https://www.terraform.io/docs/providers/datadog/index.html). diff --git a/.terraform/providers/registry.terraform.io/datadog/datadog/3.1.2/darwin_amd64/terraform-provider-datadog_v3.1.2 b/.terraform/providers/registry.terraform.io/datadog/datadog/3.1.2/darwin_amd64/terraform-provider-datadog_v3.1.2 new file mode 100755 index 0000000..44afb0a Binary files /dev/null and b/.terraform/providers/registry.terraform.io/datadog/datadog/3.1.2/darwin_amd64/terraform-provider-datadog_v3.1.2 differ diff --git a/.terraform/providers/registry.terraform.io/hashicorp/archive/2.2.0/darwin_amd64/terraform-provider-archive_v2.2.0_x5 b/.terraform/providers/registry.terraform.io/hashicorp/archive/2.2.0/darwin_amd64/terraform-provider-archive_v2.2.0_x5 new file mode 100755 index 0000000..42d225a Binary files /dev/null and b/.terraform/providers/registry.terraform.io/hashicorp/archive/2.2.0/darwin_amd64/terraform-provider-archive_v2.2.0_x5 differ diff --git a/.terraform/providers/registry.terraform.io/hashicorp/aws/3.48.0/darwin_amd64/terraform-provider-aws_v3.48.0_x5 b/.terraform/providers/registry.terraform.io/hashicorp/aws/3.48.0/darwin_amd64/terraform-provider-aws_v3.48.0_x5 new file mode 100755 index 0000000..d95a5d6 Binary files /dev/null and b/.terraform/providers/registry.terraform.io/hashicorp/aws/3.48.0/darwin_amd64/terraform-provider-aws_v3.48.0_x5 differ diff --git a/.terraform/providers/registry.terraform.io/hashicorp/external/2.1.0/darwin_amd64/terraform-provider-external_v2.1.0_x5 b/.terraform/providers/registry.terraform.io/hashicorp/external/2.1.0/darwin_amd64/terraform-provider-external_v2.1.0_x5 new file mode 100755 index 0000000..283ad6a Binary files /dev/null and b/.terraform/providers/registry.terraform.io/hashicorp/external/2.1.0/darwin_amd64/terraform-provider-external_v2.1.0_x5 differ diff --git a/.terraform/providers/registry.terraform.io/hashicorp/local/2.1.0/darwin_amd64/terraform-provider-local_v2.1.0_x5 b/.terraform/providers/registry.terraform.io/hashicorp/local/2.1.0/darwin_amd64/terraform-provider-local_v2.1.0_x5 new file mode 100755 index 0000000..334107d Binary files /dev/null and b/.terraform/providers/registry.terraform.io/hashicorp/local/2.1.0/darwin_amd64/terraform-provider-local_v2.1.0_x5 differ diff --git a/.terraform/providers/registry.terraform.io/hashicorp/template/2.2.0/darwin_amd64/terraform-provider-template_v2.2.0_x4 b/.terraform/providers/registry.terraform.io/hashicorp/template/2.2.0/darwin_amd64/terraform-provider-template_v2.2.0_x4 new file mode 100755 index 0000000..5e5a373 Binary files /dev/null and b/.terraform/providers/registry.terraform.io/hashicorp/template/2.2.0/darwin_amd64/terraform-provider-template_v2.2.0_x4 differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..ad546e2 --- /dev/null +++ b/README.md @@ -0,0 +1,157 @@ +# Terraform AWS Datadog Integration Module + +## Overview + +The `terraform-aws-datadog` module is a wrapper around the CloudPosse `datadog-integration/aws` module that automates the setup of AWS-Datadog integration. It establishes secure bidirectional communication between AWS and Datadog to enable monitoring, logging, and metrics collection from AWS services. + +## Features + +- Automated AWS-Datadog integration setup +- Multi-account support through `for_each` iteration +- IAM role and policy management for Datadog access +- Secure cross-account role assumption using external IDs +- Support for both EU and US Datadog endpoints +- Comprehensive AWS service monitoring + +## Resources Created + +This module creates the following resources: + +### AWS Resources +- **IAM Role** - Service role for Datadog to assume in AWS +- **IAM Policy** - Permissions policy allowing Datadog to access AWS resources +- **IAM Policy Attachment** - Attaches the policy to the role + +### Datadog Resources +- **Datadog AWS Integration** - Creates the integration connection with: + - External ID for security + - Role name association + - Account ID mapping + - Region configuration + - Tag filtering support + +## Usage + +```hcl +module "datadog_integration" { + source = "path/to/terraform-aws-datadog" + + region = "eu-west-1" + api_key = var.datadog_api_key # Store securely! + app_key = var.datadog_app_key # Store securely! + datadog_site = "https://api.datadoghq.eu/" + aws_profile = "your-aws-profile" + + aws_accounts = { + "production" = { + aws_account_id = "123456789012" + namespace = "datadog" + environment = "prd" + prefix_slug = "mycompany" + region = "eu-west-1" + team = "platform" + }, + "staging" = { + aws_account_id = "987654321098" + namespace = "datadog" + environment = "stg" + prefix_slug = "mycompany" + region = "eu-west-1" + team = "platform" + } + } +} +``` + +## Variables + +| Variable | Type | Required | Default | Description | +|----------|------|----------|---------|-------------| +| `region` | string | Yes | - | AWS region where resources to monitor reside | +| `api_key` | string | Yes | - | Datadog API key for sending logs, metrics, and traces | +| `app_key` | string | Yes | - | Datadog application key for API manipulation | +| `datadog_site` | string | No | `https://api.datadoghq.eu/` | Datadog API endpoint (EU or US) | +| `aws_profile` | string | Yes | - | AWS profile to use for authentication | +| `aws_accounts` | map(object) | Yes | - | Map of AWS accounts with configuration details | + +### AWS Accounts Object Structure + +Each entry in `aws_accounts` should contain: + +```hcl +{ + aws_account_id = "AWS Account ID to monitor" + namespace = "Namespace label (e.g., 'datadog')" + environment = "Environment stage (e.g., 'prd', 'stg', 'dev')" + prefix_slug = "Resource naming prefix" + region = "AWS region for the account" + team = "Team identifier for naming" +} +``` + +## Outputs + +| Output | Description | +|--------|-------------| +| `aws_account_id` | The AWS account ID integrated with Datadog | +| `aws_role_name` | Name of the IAM role created for Datadog integration | +| `datadog_external_id` | External ID used for secure role assumption | + +## Dependencies + +### External Modules +- **CloudPosse Datadog Integration AWS Module** v0.11.0 + - Source: `cloudposse/datadog-integration/aws` + +### Provider Requirements +- Datadog Provider (tested with v3.1.2) +- AWS Provider + +### Prerequisites +- Valid Datadog account with admin access +- Valid AWS account(s) to be monitored +- Datadog API key and app key with appropriate permissions +- AWS profile configured with credentials + +### Required Permissions + +**AWS Permissions:** +- IAM permissions to create roles, policies, and attachments + +**Datadog Permissions:** +- Account admin or integration admin permissions + +## Security Considerations + +- **Sensitive Data**: API keys and app keys should be stored in secure vaults (Terraform Cloud, AWS Secrets Manager, HashiCorp Vault) and never committed to version control +- **External ID**: The module uses Datadog-generated external IDs for secure cross-account role assumption +- **IAM Best Practices**: Follow principle of least privilege when configuring IAM permissions + +## Multi-Account Support + +The module uses a `for_each` loop to support multiple AWS accounts in a single Terraform run. Each integration can have its own namespace and naming convention through the configuration map. + +## Monitored Services + +When configured with "all" integrations (default), the module enables monitoring for: +- EC2 +- RDS +- ELB/ALB/NLB +- Lambda +- S3 +- CloudWatch +- And many more AWS services + +## Notes + +- Originally forked from Bitbucket (sl-technology/terraform-aws-datadog) +- Currently configured for all integrations +- Supports both EU and US Datadog endpoints + +## License + +See project license file. + +## Authors + +Maintained by WebBuildYourCloud team. diff --git a/main.tf b/main.tf old mode 100644 new mode 100755 diff --git a/outputs.tf b/outputs.tf deleted file mode 100644 index 091d06e..0000000 --- a/outputs.tf +++ /dev/null @@ -1,16 +0,0 @@ -output "aws_account_id" { - value = module.datadog_integration.aws_account_id - description = "AWS Account ID of the IAM Role for Datadog to use for this integration" -} - -output "aws_role_name" { - value = module.datadog_integration.aws_role_name - description = "Name of the AWS IAM Role for Datadog to use for this integration" -} - -output "datadog_external_id" { - value = module.datadog_integration.datadog_external_id - description = "Datadog integration external ID" -} - - diff --git a/provider.tf b/provider.tf new file mode 100755 index 0000000..77337eb --- /dev/null +++ b/provider.tf @@ -0,0 +1,14 @@ +provider "datadog" { + api_key = var.api_key + app_key = var.app_key + api_url = var.datadog_site +} + +provider "aws" { + profile = var.aws_profile + region = var.region + +# assume_role { +# role_arn = "arn:aws:iam::${var.aws_account_id}:role/role_with_deploy_rights" +# } +} diff --git a/terraform.tfstate b/terraform.tfstate new file mode 100755 index 0000000..55119cc --- /dev/null +++ b/terraform.tfstate @@ -0,0 +1,770 @@ +{ + "version": 4, + "terraform_version": "1.0.0", + "serial": 66, + "lineage": "c7241ccf-df1a-7480-0c30-60bb78015388", + "outputs": { + "aws_account_id": { + "value": "215719102928", + "type": "string" + }, + "aws_role_name": { + "value": "plaap-test-datadog-integration", + "type": "string" + }, + "datadog_external_id": { + "value": "0c446b30afab4204ab06dcfa89526ecd", + "type": "string" + } + }, + "resources": [ + { + "module": "module.datadog_integration", + "mode": "data", + "type": "aws_caller_identity", + "name": "current", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "account_id": "215719102928", + "arn": "arn:aws:iam::215719102928:user/datadog", + "id": "215719102928", + "user_id": "AIDATEOO4JHIBFNSAXC3B" + }, + "sensitive_attributes": [] + } + ] + }, + { + "module": "module.datadog_integration", + "mode": "data", + "type": "aws_iam_policy_document", + "name": "all", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "id": "1845680237", + "json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"DatadogAll\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"xray:GetTraceSummaries\",\n \"xray:BatchGetTraces\",\n \"tag:GetTagValues\",\n \"tag:GetTagKeys\",\n \"tag:GetResources\",\n \"support:*\",\n \"states:ListStateMachines\",\n \"states:DescribeStateMachine\",\n \"sqs:ListQueues\",\n \"sns:Publish\",\n \"sns:List*\",\n \"ses:Get*\",\n \"s3:PutBucketNotification\",\n \"s3:ListAllMyBuckets\",\n \"s3:GetBucketTagging\",\n \"s3:GetBucketNotification\",\n \"s3:GetBucketLogging\",\n \"s3:GetBucketLocation\",\n \"route53:List*\",\n \"redshift:DescribeLoggingStatus\",\n \"redshift:DescribeClusters\",\n \"rds:List*\",\n \"rds:Describe*\",\n \"logs:TestMetricFilter\",\n \"logs:PutSubscriptionFilter\",\n \"logs:DescribeSubscriptionFilters\",\n \"logs:DeleteSubscriptionFilter\",\n \"lambda:RemovePermission\",\n \"lambda:List*\",\n \"lambda:GetPolicy\",\n \"lambda:AddPermission\",\n \"kinesis:List*\",\n \"kinesis:Describe*\",\n \"health:DescribeEvents\",\n \"health:DescribeEventDetails\",\n \"health:DescribeAffectedEntities\",\n \"es:ListTags\",\n \"es:ListDomainNames\",\n \"es:DescribeElasticsearchDomains\",\n \"elasticmapreduce:List*\",\n \"elasticmapreduce:Describe*\",\n \"elasticloadbalancing:Describe*\",\n \"elasticfilesystem:DescribeTags\",\n \"elasticfilesystem:DescribeFileSystems\",\n \"elasticache:List*\",\n \"elasticache:Describe*\",\n \"ecs:List*\",\n \"ecs:Describe*\",\n \"ec2:Describe*\",\n \"dynamodb:List*\",\n \"dynamodb:Describe*\",\n \"directconnect:Describe*\",\n \"codedeploy:List*\",\n \"codedeploy:BatchGet*\",\n \"cloudwatch:List*\",\n \"cloudwatch:Get*\",\n \"cloudwatch:Describe*\",\n \"cloudtrail:GetTrailStatus\",\n \"cloudtrail:DescribeTrails\",\n \"cloudfront:ListDistributions\",\n \"cloudfront:GetDistributionConfig\",\n \"budgets:ViewBudget\",\n \"autoscaling:Describe*\",\n \"apigateway:GET\"\n ],\n \"Resource\": \"*\"\n }\n ]\n}", + "override_json": null, + "override_policy_documents": null, + "policy_id": null, + "source_json": null, + "source_policy_documents": null, + "statement": [ + { + "actions": [ + "apigateway:GET", + "autoscaling:Describe*", + "budgets:ViewBudget", + "cloudfront:GetDistributionConfig", + "cloudfront:ListDistributions", + "cloudtrail:DescribeTrails", + "cloudtrail:GetTrailStatus", + "cloudwatch:Describe*", + "cloudwatch:Get*", + "cloudwatch:List*", + "codedeploy:BatchGet*", + "codedeploy:List*", + "directconnect:Describe*", + "dynamodb:Describe*", + "dynamodb:List*", + "ec2:Describe*", + "ecs:Describe*", + "ecs:List*", + "elasticache:Describe*", + "elasticache:List*", + "elasticfilesystem:DescribeFileSystems", + "elasticfilesystem:DescribeTags", + "elasticloadbalancing:Describe*", + "elasticmapreduce:Describe*", + "elasticmapreduce:List*", + "es:DescribeElasticsearchDomains", + "es:ListDomainNames", + "es:ListTags", + "health:DescribeAffectedEntities", + "health:DescribeEventDetails", + "health:DescribeEvents", + "kinesis:Describe*", + "kinesis:List*", + "lambda:AddPermission", + "lambda:GetPolicy", + "lambda:List*", + "lambda:RemovePermission", + "logs:DeleteSubscriptionFilter", + "logs:DescribeSubscriptionFilters", + "logs:PutSubscriptionFilter", + "logs:TestMetricFilter", + "rds:Describe*", + "rds:List*", + "redshift:DescribeClusters", + "redshift:DescribeLoggingStatus", + "route53:List*", + "s3:GetBucketLocation", + "s3:GetBucketLogging", + "s3:GetBucketNotification", + "s3:GetBucketTagging", + "s3:ListAllMyBuckets", + "s3:PutBucketNotification", + "ses:Get*", + "sns:List*", + "sns:Publish", + "sqs:ListQueues", + "states:DescribeStateMachine", + "states:ListStateMachines", + "support:*", + "tag:GetResources", + "tag:GetTagKeys", + "tag:GetTagValues", + "xray:BatchGetTraces", + "xray:GetTraceSummaries" + ], + "condition": [], + "effect": "Allow", + "not_actions": [], + "not_principals": [], + "not_resources": [], + "principals": [], + "resources": [ + "*" + ], + "sid": "DatadogAll" + } + ], + "version": "2012-10-17" + }, + "sensitive_attributes": [] + } + ] + }, + { + "module": "module.datadog_integration", + "mode": "data", + "type": "aws_iam_policy_document", + "name": "assume_role", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "id": "243323576", + "json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"DatadogAWSTrustRelationship\",\n \"Effect\": \"Allow\",\n \"Action\": \"sts:AssumeRole\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::464622532012:root\"\n },\n \"Condition\": {\n \"StringEquals\": {\n \"sts:ExternalId\": [\n \"0c446b30afab4204ab06dcfa89526ecd\"\n ]\n }\n }\n }\n ]\n}", + "override_json": null, + "override_policy_documents": null, + "policy_id": null, + "source_json": null, + "source_policy_documents": null, + "statement": [ + { + "actions": [ + "sts:AssumeRole" + ], + "condition": [ + { + "test": "StringEquals", + "values": [ + "0c446b30afab4204ab06dcfa89526ecd" + ], + "variable": "sts:ExternalId" + } + ], + "effect": "Allow", + "not_actions": [], + "not_principals": [], + "not_resources": [], + "principals": [ + { + "identifiers": [ + "arn:aws:iam::464622532012:root" + ], + "type": "AWS" + } + ], + "resources": [], + "sid": "DatadogAWSTrustRelationship" + } + ], + "version": "2012-10-17" + }, + "sensitive_attributes": [] + } + ] + }, + { + "module": "module.datadog_integration", + "mode": "data", + "type": "aws_iam_policy_document", + "name": "core", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "id": "2056658824", + "json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"DatadogCore\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"tag:GetTagValues\",\n \"tag:GetTagKeys\",\n \"tag:GetResources\",\n \"support:*\",\n \"ec2:Describe*\",\n \"cloudwatch:List*\",\n \"cloudwatch:Get*\"\n ],\n \"Resource\": \"*\"\n }\n ]\n}", + "override_json": null, + "override_policy_documents": null, + "policy_id": null, + "source_json": null, + "source_policy_documents": null, + "statement": [ + { + "actions": [ + "cloudwatch:Get*", + "cloudwatch:List*", + "ec2:Describe*", + "support:*", + "tag:GetResources", + "tag:GetTagKeys", + "tag:GetTagValues" + ], + "condition": [], + "effect": "Allow", + "not_actions": [], + "not_principals": [], + "not_resources": [], + "principals": [], + "resources": [ + "*" + ], + "sid": "DatadogCore" + } + ], + "version": "2012-10-17" + }, + "sensitive_attributes": [] + } + ] + }, + { + "module": "module.datadog_integration", + "mode": "data", + "type": "aws_region", + "name": "current", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "description": "Europe (Ireland)", + "endpoint": "ec2.eu-west-1.amazonaws.com", + "id": "eu-west-1", + "name": "eu-west-1" + }, + "sensitive_attributes": [] + } + ] + }, + { + "module": "module.datadog_integration", + "mode": "managed", + "type": "aws_iam_policy", + "name": "all", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:iam::215719102928:policy/plaap-test-datadog-integration-all", + "description": "", + "id": "arn:aws:iam::215719102928:policy/plaap-test-datadog-integration-all", + "name": "plaap-test-datadog-integration-all", + "name_prefix": null, + "path": "/", + "policy": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"DatadogAll\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"xray:GetTraceSummaries\",\n \"xray:BatchGetTraces\",\n \"tag:GetTagValues\",\n \"tag:GetTagKeys\",\n \"tag:GetResources\",\n \"support:*\",\n \"states:ListStateMachines\",\n \"states:DescribeStateMachine\",\n \"sqs:ListQueues\",\n \"sns:Publish\",\n \"sns:List*\",\n \"ses:Get*\",\n \"s3:PutBucketNotification\",\n \"s3:ListAllMyBuckets\",\n \"s3:GetBucketTagging\",\n \"s3:GetBucketNotification\",\n \"s3:GetBucketLogging\",\n \"s3:GetBucketLocation\",\n \"route53:List*\",\n \"redshift:DescribeLoggingStatus\",\n \"redshift:DescribeClusters\",\n \"rds:List*\",\n \"rds:Describe*\",\n \"logs:TestMetricFilter\",\n \"logs:PutSubscriptionFilter\",\n \"logs:DescribeSubscriptionFilters\",\n \"logs:DeleteSubscriptionFilter\",\n \"lambda:RemovePermission\",\n \"lambda:List*\",\n \"lambda:GetPolicy\",\n \"lambda:AddPermission\",\n \"kinesis:List*\",\n \"kinesis:Describe*\",\n \"health:DescribeEvents\",\n \"health:DescribeEventDetails\",\n \"health:DescribeAffectedEntities\",\n \"es:ListTags\",\n \"es:ListDomainNames\",\n \"es:DescribeElasticsearchDomains\",\n \"elasticmapreduce:List*\",\n \"elasticmapreduce:Describe*\",\n \"elasticloadbalancing:Describe*\",\n \"elasticfilesystem:DescribeTags\",\n \"elasticfilesystem:DescribeFileSystems\",\n \"elasticache:List*\",\n \"elasticache:Describe*\",\n \"ecs:List*\",\n \"ecs:Describe*\",\n \"ec2:Describe*\",\n \"dynamodb:List*\",\n \"dynamodb:Describe*\",\n \"directconnect:Describe*\",\n \"codedeploy:List*\",\n \"codedeploy:BatchGet*\",\n \"cloudwatch:List*\",\n \"cloudwatch:Get*\",\n \"cloudwatch:Describe*\",\n \"cloudtrail:GetTrailStatus\",\n \"cloudtrail:DescribeTrails\",\n \"cloudfront:ListDistributions\",\n \"cloudfront:GetDistributionConfig\",\n \"budgets:ViewBudget\",\n \"autoscaling:Describe*\",\n \"apigateway:GET\"\n ],\n \"Resource\": \"*\"\n }\n ]\n}", + "policy_id": "ANPATEOO4JHIDGLAVHEXW", + "tags": null, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "module.datadog_integration.data.aws_iam_policy_document.all" + ] + } + ] + }, + { + "module": "module.datadog_integration", + "mode": "managed", + "type": "aws_iam_role", + "name": "default", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:iam::215719102928:role/plaap-test-datadog-integration", + "assume_role_policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"DatadogAWSTrustRelationship\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::464622532012:root\"},\"Action\":\"sts:AssumeRole\",\"Condition\":{\"StringEquals\":{\"sts:ExternalId\":\"0c446b30afab4204ab06dcfa89526ecd\"}}}]}", + "create_date": "2021-09-09T09:27:58Z", + "description": "", + "force_detach_policies": false, + "id": "plaap-test-datadog-integration", + "inline_policy": [ + { + "name": "", + "policy": "" + } + ], + "managed_policy_arns": [], + "max_session_duration": 3600, + "name": "plaap-test-datadog-integration", + "name_prefix": null, + "path": "/", + "permissions_boundary": null, + "tags": null, + "tags_all": {}, + "unique_id": "AROATEOO4JHIKD2HBQVXF" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "module.datadog_integration.data.aws_iam_policy_document.assume_role" + ] + } + ] + }, + { + "module": "module.datadog_integration", + "mode": "managed", + "type": "aws_iam_role_policy_attachment", + "name": "all", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "id": "plaap-test-datadog-integration-20210909092800093600000001", + "policy_arn": "arn:aws:iam::215719102928:policy/plaap-test-datadog-integration-all", + "role": "plaap-test-datadog-integration" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "module.datadog_integration.aws_iam_policy.all", + "module.datadog_integration.aws_iam_role.default", + "module.datadog_integration.data.aws_iam_policy_document.all", + "module.datadog_integration.data.aws_iam_policy_document.assume_role" + ] + } + ] + }, + { + "module": "module.datadog_integration", + "mode": "managed", + "type": "datadog_integration_aws", + "name": "integration", + "provider": "provider[\"registry.terraform.io/datadog/datadog\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "access_key_id": "", + "account_id": "215719102928", + "account_specific_namespace_rules": {}, + "excluded_regions": [], + "external_id": "0c446b30afab4204ab06dcfa89526ecd", + "filter_tags": [], + "host_tags": [], + "id": "215719102928:plaap-test-datadog-integration", + "role_name": "plaap-test-datadog-integration", + "secret_access_key": null + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "module.datadog_integration.data.aws_caller_identity.current" + ] + } + ] + }, + { + "module": "module.datadog_integration2", + "mode": "data", + "type": "aws_caller_identity", + "name": "current", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "account_id": "215719102928", + "arn": "arn:aws:iam::215719102928:user/datadog", + "id": "215719102928", + "user_id": "AIDATEOO4JHIBFNSAXC3B" + }, + "sensitive_attributes": [] + } + ] + }, + { + "module": "module.datadog_integration2", + "mode": "data", + "type": "aws_iam_policy_document", + "name": "all", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "id": "1845680237", + "json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"DatadogAll\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"xray:GetTraceSummaries\",\n \"xray:BatchGetTraces\",\n \"tag:GetTagValues\",\n \"tag:GetTagKeys\",\n \"tag:GetResources\",\n \"support:*\",\n \"states:ListStateMachines\",\n \"states:DescribeStateMachine\",\n \"sqs:ListQueues\",\n \"sns:Publish\",\n \"sns:List*\",\n \"ses:Get*\",\n \"s3:PutBucketNotification\",\n \"s3:ListAllMyBuckets\",\n \"s3:GetBucketTagging\",\n \"s3:GetBucketNotification\",\n \"s3:GetBucketLogging\",\n \"s3:GetBucketLocation\",\n \"route53:List*\",\n \"redshift:DescribeLoggingStatus\",\n \"redshift:DescribeClusters\",\n \"rds:List*\",\n \"rds:Describe*\",\n \"logs:TestMetricFilter\",\n \"logs:PutSubscriptionFilter\",\n \"logs:DescribeSubscriptionFilters\",\n \"logs:DeleteSubscriptionFilter\",\n \"lambda:RemovePermission\",\n \"lambda:List*\",\n \"lambda:GetPolicy\",\n \"lambda:AddPermission\",\n \"kinesis:List*\",\n \"kinesis:Describe*\",\n \"health:DescribeEvents\",\n \"health:DescribeEventDetails\",\n \"health:DescribeAffectedEntities\",\n \"es:ListTags\",\n \"es:ListDomainNames\",\n \"es:DescribeElasticsearchDomains\",\n \"elasticmapreduce:List*\",\n \"elasticmapreduce:Describe*\",\n \"elasticloadbalancing:Describe*\",\n \"elasticfilesystem:DescribeTags\",\n \"elasticfilesystem:DescribeFileSystems\",\n \"elasticache:List*\",\n \"elasticache:Describe*\",\n \"ecs:List*\",\n \"ecs:Describe*\",\n \"ec2:Describe*\",\n \"dynamodb:List*\",\n \"dynamodb:Describe*\",\n \"directconnect:Describe*\",\n \"codedeploy:List*\",\n \"codedeploy:BatchGet*\",\n \"cloudwatch:List*\",\n \"cloudwatch:Get*\",\n \"cloudwatch:Describe*\",\n \"cloudtrail:GetTrailStatus\",\n \"cloudtrail:DescribeTrails\",\n \"cloudfront:ListDistributions\",\n \"cloudfront:GetDistributionConfig\",\n \"budgets:ViewBudget\",\n \"autoscaling:Describe*\",\n \"apigateway:GET\"\n ],\n \"Resource\": \"*\"\n }\n ]\n}", + "override_json": null, + "override_policy_documents": null, + "policy_id": null, + "source_json": null, + "source_policy_documents": null, + "statement": [ + { + "actions": [ + "apigateway:GET", + "autoscaling:Describe*", + "budgets:ViewBudget", + "cloudfront:GetDistributionConfig", + "cloudfront:ListDistributions", + "cloudtrail:DescribeTrails", + "cloudtrail:GetTrailStatus", + "cloudwatch:Describe*", + "cloudwatch:Get*", + "cloudwatch:List*", + "codedeploy:BatchGet*", + "codedeploy:List*", + "directconnect:Describe*", + "dynamodb:Describe*", + "dynamodb:List*", + "ec2:Describe*", + "ecs:Describe*", + "ecs:List*", + "elasticache:Describe*", + "elasticache:List*", + "elasticfilesystem:DescribeFileSystems", + "elasticfilesystem:DescribeTags", + "elasticloadbalancing:Describe*", + "elasticmapreduce:Describe*", + "elasticmapreduce:List*", + "es:DescribeElasticsearchDomains", + "es:ListDomainNames", + "es:ListTags", + "health:DescribeAffectedEntities", + "health:DescribeEventDetails", + "health:DescribeEvents", + "kinesis:Describe*", + "kinesis:List*", + "lambda:AddPermission", + "lambda:GetPolicy", + "lambda:List*", + "lambda:RemovePermission", + "logs:DeleteSubscriptionFilter", + "logs:DescribeSubscriptionFilters", + "logs:PutSubscriptionFilter", + "logs:TestMetricFilter", + "rds:Describe*", + "rds:List*", + "redshift:DescribeClusters", + "redshift:DescribeLoggingStatus", + "route53:List*", + "s3:GetBucketLocation", + "s3:GetBucketLogging", + "s3:GetBucketNotification", + "s3:GetBucketTagging", + "s3:ListAllMyBuckets", + "s3:PutBucketNotification", + "ses:Get*", + "sns:List*", + "sns:Publish", + "sqs:ListQueues", + "states:DescribeStateMachine", + "states:ListStateMachines", + "support:*", + "tag:GetResources", + "tag:GetTagKeys", + "tag:GetTagValues", + "xray:BatchGetTraces", + "xray:GetTraceSummaries" + ], + "condition": [], + "effect": "Allow", + "not_actions": [], + "not_principals": [], + "not_resources": [], + "principals": [], + "resources": [ + "*" + ], + "sid": "DatadogAll" + } + ], + "version": "2012-10-17" + }, + "sensitive_attributes": [] + } + ] + }, + { + "module": "module.datadog_integration2", + "mode": "data", + "type": "aws_iam_policy_document", + "name": "assume_role", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "id": "1420647941", + "json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"DatadogAWSTrustRelationship\",\n \"Effect\": \"Allow\",\n \"Action\": \"sts:AssumeRole\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::464622532012:root\"\n },\n \"Condition\": {\n \"StringEquals\": {\n \"sts:ExternalId\": [\n \"243c9e65587b4aa4a21610700610537b\"\n ]\n }\n }\n }\n ]\n}", + "override_json": null, + "override_policy_documents": null, + "policy_id": null, + "source_json": null, + "source_policy_documents": null, + "statement": [ + { + "actions": [ + "sts:AssumeRole" + ], + "condition": [ + { + "test": "StringEquals", + "values": [ + "243c9e65587b4aa4a21610700610537b" + ], + "variable": "sts:ExternalId" + } + ], + "effect": "Allow", + "not_actions": [], + "not_principals": [], + "not_resources": [], + "principals": [ + { + "identifiers": [ + "arn:aws:iam::464622532012:root" + ], + "type": "AWS" + } + ], + "resources": [], + "sid": "DatadogAWSTrustRelationship" + } + ], + "version": "2012-10-17" + }, + "sensitive_attributes": [] + } + ] + }, + { + "module": "module.datadog_integration2", + "mode": "data", + "type": "aws_iam_policy_document", + "name": "core", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "id": "2056658824", + "json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"DatadogCore\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"tag:GetTagValues\",\n \"tag:GetTagKeys\",\n \"tag:GetResources\",\n \"support:*\",\n \"ec2:Describe*\",\n \"cloudwatch:List*\",\n \"cloudwatch:Get*\"\n ],\n \"Resource\": \"*\"\n }\n ]\n}", + "override_json": null, + "override_policy_documents": null, + "policy_id": null, + "source_json": null, + "source_policy_documents": null, + "statement": [ + { + "actions": [ + "cloudwatch:Get*", + "cloudwatch:List*", + "ec2:Describe*", + "support:*", + "tag:GetResources", + "tag:GetTagKeys", + "tag:GetTagValues" + ], + "condition": [], + "effect": "Allow", + "not_actions": [], + "not_principals": [], + "not_resources": [], + "principals": [], + "resources": [ + "*" + ], + "sid": "DatadogCore" + } + ], + "version": "2012-10-17" + }, + "sensitive_attributes": [] + } + ] + }, + { + "module": "module.datadog_integration2", + "mode": "data", + "type": "aws_region", + "name": "current", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "description": "Europe (Ireland)", + "endpoint": "ec2.eu-west-1.amazonaws.com", + "id": "eu-west-1", + "name": "eu-west-1" + }, + "sensitive_attributes": [] + } + ] + }, + { + "module": "module.datadog_integration2", + "mode": "managed", + "type": "aws_iam_policy", + "name": "all", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:iam::215719102928:policy/datadog-test-datadog-integration-all", + "description": "", + "id": "arn:aws:iam::215719102928:policy/datadog-test-datadog-integration-all", + "name": "datadog-test-datadog-integration-all", + "name_prefix": null, + "path": "/", + "policy": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"DatadogAll\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"xray:GetTraceSummaries\",\n \"xray:BatchGetTraces\",\n \"tag:GetTagValues\",\n \"tag:GetTagKeys\",\n \"tag:GetResources\",\n \"support:*\",\n \"states:ListStateMachines\",\n \"states:DescribeStateMachine\",\n \"sqs:ListQueues\",\n \"sns:Publish\",\n \"sns:List*\",\n \"ses:Get*\",\n \"s3:PutBucketNotification\",\n \"s3:ListAllMyBuckets\",\n \"s3:GetBucketTagging\",\n \"s3:GetBucketNotification\",\n \"s3:GetBucketLogging\",\n \"s3:GetBucketLocation\",\n \"route53:List*\",\n \"redshift:DescribeLoggingStatus\",\n \"redshift:DescribeClusters\",\n \"rds:List*\",\n \"rds:Describe*\",\n \"logs:TestMetricFilter\",\n \"logs:PutSubscriptionFilter\",\n \"logs:DescribeSubscriptionFilters\",\n \"logs:DeleteSubscriptionFilter\",\n \"lambda:RemovePermission\",\n \"lambda:List*\",\n \"lambda:GetPolicy\",\n \"lambda:AddPermission\",\n \"kinesis:List*\",\n \"kinesis:Describe*\",\n \"health:DescribeEvents\",\n \"health:DescribeEventDetails\",\n \"health:DescribeAffectedEntities\",\n \"es:ListTags\",\n \"es:ListDomainNames\",\n \"es:DescribeElasticsearchDomains\",\n \"elasticmapreduce:List*\",\n \"elasticmapreduce:Describe*\",\n \"elasticloadbalancing:Describe*\",\n \"elasticfilesystem:DescribeTags\",\n \"elasticfilesystem:DescribeFileSystems\",\n \"elasticache:List*\",\n \"elasticache:Describe*\",\n \"ecs:List*\",\n \"ecs:Describe*\",\n \"ec2:Describe*\",\n \"dynamodb:List*\",\n \"dynamodb:Describe*\",\n \"directconnect:Describe*\",\n \"codedeploy:List*\",\n \"codedeploy:BatchGet*\",\n \"cloudwatch:List*\",\n \"cloudwatch:Get*\",\n \"cloudwatch:Describe*\",\n \"cloudtrail:GetTrailStatus\",\n \"cloudtrail:DescribeTrails\",\n \"cloudfront:ListDistributions\",\n \"cloudfront:GetDistributionConfig\",\n \"budgets:ViewBudget\",\n \"autoscaling:Describe*\",\n \"apigateway:GET\"\n ],\n \"Resource\": \"*\"\n }\n ]\n}", + "policy_id": "ANPATEOO4JHICQN63W7MF", + "tags": null, + "tags_all": {} + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "module.datadog_integration2.data.aws_iam_policy_document.all" + ] + } + ] + }, + { + "module": "module.datadog_integration2", + "mode": "managed", + "type": "aws_iam_role", + "name": "default", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws:iam::215719102928:role/datadog-test-datadog-integration", + "assume_role_policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"DatadogAWSTrustRelationship\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::464622532012:root\"},\"Action\":\"sts:AssumeRole\",\"Condition\":{\"StringEquals\":{\"sts:ExternalId\":\"243c9e65587b4aa4a21610700610537b\"}}}]}", + "create_date": "2021-09-09T09:27:59Z", + "description": "", + "force_detach_policies": false, + "id": "datadog-test-datadog-integration", + "inline_policy": [ + { + "name": "", + "policy": "" + } + ], + "managed_policy_arns": [], + "max_session_duration": 3600, + "name": "datadog-test-datadog-integration", + "name_prefix": null, + "path": "/", + "permissions_boundary": null, + "tags": null, + "tags_all": {}, + "unique_id": "AROATEOO4JHIPYWKBSOLE" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "module.datadog_integration2.data.aws_caller_identity.current", + "module.datadog_integration2.data.aws_iam_policy_document.assume_role", + "module.datadog_integration2.datadog_integration_aws.integration" + ] + } + ] + }, + { + "module": "module.datadog_integration2", + "mode": "managed", + "type": "aws_iam_role_policy_attachment", + "name": "all", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "id": "datadog-test-datadog-integration-20210909092801648400000002", + "policy_arn": "arn:aws:iam::215719102928:policy/datadog-test-datadog-integration-all", + "role": "datadog-test-datadog-integration" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "module.datadog_integration2.aws_iam_policy.all", + "module.datadog_integration2.aws_iam_role.default", + "module.datadog_integration2.data.aws_caller_identity.current", + "module.datadog_integration2.data.aws_iam_policy_document.all", + "module.datadog_integration2.data.aws_iam_policy_document.assume_role", + "module.datadog_integration2.datadog_integration_aws.integration" + ] + } + ] + }, + { + "module": "module.datadog_integration2", + "mode": "managed", + "type": "datadog_integration_aws", + "name": "integration", + "provider": "provider[\"registry.terraform.io/datadog/datadog\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "access_key_id": "", + "account_id": "215719102928", + "account_specific_namespace_rules": null, + "excluded_regions": null, + "external_id": "243c9e65587b4aa4a21610700610537b", + "filter_tags": null, + "host_tags": null, + "id": "215719102928:datadog-test-datadog-integration", + "role_name": "datadog-test-datadog-integration", + "secret_access_key": null + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "module.datadog_integration2.data.aws_caller_identity.current" + ] + } + ] + } + ] +} diff --git a/terraform.tfvars b/terraform.tfvars new file mode 100755 index 0000000..227e3a2 --- /dev/null +++ b/terraform.tfvars @@ -0,0 +1,10 @@ +# These variables are the same for all AWS accounts, and can be stored as a generaly available variable +region = "eu-west-1" +api_key = "2fcc093ed06e4dbe0935433495898cad" +app_key = "aaf4a9654b82cfa8b23b2d65801901a4ad9d35ed" +datadog_site = "https://api.datadoghq.eu/" +namespace = "datadog" + +# These variables are unique for each AWS account +#aws_profile = "ws-playground-applicatiebeheer" +aws_profile = "dd_belgie" diff --git a/variables.tf b/variables.tf old mode 100644 new mode 100755 diff --git a/versions.tf b/versions.tf deleted file mode 100644 index 6e26982..0000000 --- a/versions.tf +++ /dev/null @@ -1,18 +0,0 @@ -terraform { - required_version = ">= 0.13.0" - - required_providers { - aws = { - source = "hashicorp/aws" - #version = ">= 2.0" - } - local = { - source = "hashicorp/local" - version = ">= 1.3" - } - datadog = { - source = "datadog/datadog" - #version = ">= 2.12" - } - } -}